The Raku Programming Language


  • Considered Harmful

    @pie_flavor said in The Raku Programming Language:

    Raku allows both. Why? No reason.

    To say nothing of the ways of actually passing named parameters. You might say func(:name($val)), or you might say func(name => $val). If both things have the same name, you might just say func(:$val). If you just want to pass True, you might say func(:name), and if you just want to pass False, you might say func(:!name). If $val is a numeric literal, you might say func(:35name). If $val is a string literal consisting of a single word, you might say func(:name<wharrgarbl>). And all of these except => can be used as adverbs: func(other-things):name is the same call as func(other-things, name => True). This leads to interesting syntax, for example to check if a key is in a hash you would say %things{$thing}:exists. (Hash indexing also does the word thing; %things<name>:exists.) Note also that name => $val should not be accidentally confused with 'name' => $val, which instead constructs a Pair object.


  • BINNED

    Do we have enough crazy syntax yet? We need more syntax. It’s syntax all the way down.



  • @topspin said in The Raku Programming Language:

    Do we have enough crazy syntax yet? We need more syntax. It’s syntax all the way down.

    Yeah. So it wasn't pot that they were on. Something a bit more psychedelic. It's Bad Drug Trip, the language.


  • Considered Harmful

    @topspin More syntax? Okay. Ruby is the (or an) originator of function-name if $condition syntax, but unless I am mistaken, function-name($^elem) for @elems is entirely Raku in origin. Like @elems».&function-name, but all on the same thread.



  • @pie_flavor said in The Raku Programming Language:

    @topspin More syntax? Okay. Ruby is the (or an) originator of function-name if $condition syntax

    Didn't Ruby borrow that from Perl? Not 100% sure, but I think that Perl did it and Ruby copied it.



  • @Mason_Wheeler I don't know Ruby at all (and I'd like to keep it that way, TYVM), but Perl definitely has statement if (condition); syntax, and has had it as long as I've been using it, which (I think) is longer than Ruby's been around.



  • @pie_flavor said in The Raku Programming Language:

    Like @elems».&function-name, but all on the same thread.

    Wait, Raku has an "I accidentally the whole threadpool" operator? And it's indistinguishable from Latin-1/UTF-8 mojibake?



  • @pie_flavor said in The Raku Programming Language:

    Finally, sub foo { $^a / $^b } is a different function from sub foo { $^b / $^a }, because such auto-params are ordered alphabetically

    You know I was on board with most of that post until this bit. Named auto-variables is actually not a bad feature. But using letter ordering (particularly given that presumably those names can be $^δ and $^з?) is a WTF. I don't think there's really a sane way to do implicit parameters for more than one tbh.


  • Discourse touched me in a no-no place

    @bobjanova said in The Raku Programming Language:

    I don't think there's really a sane way

    QFFT about the whole of Raku.

    And yes, alphabetic ordering of auto-parameters is off the scale.


  • Considered Harmful

    @TwelveBaud Yes, I must of forgot to mention. The reason that @x».y does not guarantee the same order of operations as in the list is because it's executed over several threads.



  • @bobjanova said in The Raku Programming Language:

    presumably those names can be $^🦋 and $^敗

    FTFR



  • @Watson said in The Raku Programming Language:

    @bobjanova said in The Raku Programming Language:

    presumably those names can be $^🦋 and $^敗

    FTFR

    From what I've read in this thread, I'm pretty sure this is the only "fix" for Raku:
    0da7d7a0-2f0e-4ac6-957e-599a1f6b032f-image.png


  • ♿ (Parody)

    @pie_flavor said in The Raku Programming Language:

    You may notice that I use both Java-style a.b(c) syntax and Ruby-style a.b c syntax for function invocation. Raku allows both. Why? No reason.

    Pretty sure the reason is because perl already does that sort of thing, so when you say "Ruby-style" you really mean perl-style.

    To call subroutines:

        NAME(LIST);	   # & is optional with parentheses.
        NAME LIST;	   # Parentheses optional if predeclared/imported.
        &NAME(LIST);   # Circumvent prototypes.
        &NAME;	   # Makes current @_ visible to called subroutine.
    

  • ♿ (Parody)

    @Benjamin-Hall said in The Raku Programming Language:

    @pie_flavor the more I read about Raku, the more it sounds like the devs were on a really long lasting pot high the whole time. Sure man, that sounds good. Just throw it in! Pass the Cheetos!

    It sounds like one giant experiment.

    Hey, this sounds interesting. Wonder if we could make it work?

    Over and over and over. The end result is a dog's breakfast, but used judiciously, I'll bet there are some really good ideas in there that might hopefully make their way out and be used in a saner environment.


  • ♿ (Parody)

    @pie_flavor said in The Raku Programming Language:

    @topspin More syntax? Okay. Ruby is the (or an) originator of function-name if $condition syntax

    Once again, your lack of perl knowledge is showing. There's also unless that's used in the same way. Most famously as:

    die unless some_error_check_was_ok();



  • @boomzilla said in The Raku Programming Language:

    The end result is a dog's breakfast

    More like the undigested remnant that comes out the other end.

    I'll bet there are some really good ideas in there

    I'm very skeptical of that, but even if there are, I don't care to look through the 💩 to find them.



  • @boomzilla said in The Raku Programming Language:

    your lack of perl knowledge is showing

    Isn't that usually considered a good thing?


  • ♿ (Parody)

    @HardwareGeek said in The Raku Programming Language:

    @boomzilla said in The Raku Programming Language:

    your lack of perl knowledge is showing

    Isn't that usually considered a good thing?

    For sure, but misplaces some of the blame when you're reviewing something that grew out of it. The Raku guys are a special kind of nut, but it shouldn't be forgotten how much of their wackiness (and also Ruby's) grew out of Larry Wall's original delusions and the cult that followed him.


  • Considered Harmful

    @boomzilla The entire thing grew out of Larry Wall's original delusions. He made the language. The community still operates by Rule 1.


  • ♿ (Parody)

    @pie_flavor Yes, but I think it's fair to call the Raku / Perl split a schism, which is what I was referring to.


  • Discourse touched me in a no-no place

    @boomzilla said in The Raku Programming Language:

    I think it's fair to call the Raku / Perl split a schism

    The real schism is Perl 7.


  • BINNED

    @boomzilla said in The Raku Programming Language:

    die unless some_error_check_was_ok();

    This is probably the only construct where I can read that without thinking too much about it. And it's a pretty special case.
    Might just be not being used to it, but I have a significantly harder time understanding

    unless (condition)
       foo()
    

    than

    if (not condition)
       foo()
    

    (Whatever the correct syntax for this actually is)


  • ♿ (Parody)

    @topspin yeah, one orders based on natural language (English, at least, YMLMMV), the other uses the sort of C-like programming notation that requires you to think differently.

    I think the unless(condition){...} thing is weird mostly because we're used to having negation in the condition itself (which is to say that I agree with you).


  • Considered Harmful

    Despite all these features, Raku is still a one-pass language. That means modules can't be circular, mutually recursive functions require forward declarations, and all the other fun things you normally come across.



  • @pie_flavor
    Now I'm curious how many :wtf:s are hidden in the compiler itself. Judging by the sanity of the language designers, you should find quite a few.


  • Discourse touched me in a no-no place

    @pie_flavor said in The Raku Programming Language:

    Despite all these features, Raku is still a one-pass language. That means modules can't be circular, mutually recursive functions require forward declarations, and all the other fun things you normally come across.

    So it's not only one-pass but also early binding. Early binding is… primitive. It's especially primitive without a link phase.

    With late binding, circular features aren't a problem necessarily, since the calls are not actually bound to the implementations until they're actually called. Provided the functions and objects actually exist by then, everything works. Extra tools are required to work out ahead of time if a thing actually is going to be bound… but simply testing the code is good enough to usually prove that. Efficient implementations of late binding require clever caches.

    Java and C# use a third approach: simultaneous binding. Logically everything is declared at the same time. That's nice for the programmer, but complicated for the compiler writer. (This sort of thing is part of why tools like make don't really work for these languages; they have to have everything rebuilt effectively at once.)



  • @dkf said in The Raku Programming Language:

    @pie_flavor said in The Raku Programming Language:

    Despite all these features, Raku is still a one-pass language. That means modules can't be circular, mutually recursive functions require forward declarations, and all the other fun things you normally come across.

    So it's not only one-pass but also early binding. Early binding is… primitive. It's especially primitive without a link phase.

    With late binding, circular features aren't a problem necessarily, since the calls are not actually bound to the implementations until they're actually called. Provided the functions and objects actually exist by then, everything works. Extra tools are required to work out ahead of time if a thing actually is going to be bound… but simply testing the code is good enough to usually prove that. Efficient implementations of late binding require clever caches.

    Java and C# use a third approach: simultaneous binding. Logically everything is declared at the same time. That's nice for the programmer, but complicated for the compiler writer.

    ❓

    I've never heard the terms "early/late binding" used in this way. Generally it refers to how static (early) or dynamic (late) a language's symbol resolution and function dispatch mechanism is.

    (This sort of thing is part of why tools like make don't really work for these languages; they have to have everything rebuilt effectively at once.)

    This feels like a vacuous truth, since the set of languages that make does work well for is empty. 🚎



  • @Mason_Wheeler said in The Raku Programming Language:

    This feels like a vacuous truth, since the set of languages that make does work well for is empty.

    Also, the "list of software that cannot handle spaces in paths" thread is :arrows:.


  • Discourse touched me in a no-no place

    @Mason_Wheeler said in The Raku Programming Language:

    I've never heard the terms "early/late binding" used in this way. Generally it refers to how static (early) or dynamic (late) a language's symbol resolution and function dispatch mechanism is.

    They're related. Binding is actually the part where a symbol's name in a particular use is coupled to its meaning in that use. The symbol might be naming a function or a variable or a constant or a type or whatever. In C, the lookup is done immediately by the compiler during parsing of the code (early binding). In other languages, the lookup is done at the time of use (late binding). In simultaneous binding, all symbols in the language are conceptually declared at the same time; that's great except for the cases where it isn't true and then you're into proper 🤯 territory. In late binding, you've also got whether the call site can be rebound: that's a concept that doesn't really make much sense with early binding (unless you do major hacks with linking).

    Actual function dispatch is something else, and always post-binding. The dispatch phase itself requires the implementation of the thing which is being dispatched to.



  • @dkf said in The Raku Programming Language:

    @Mason_Wheeler said in The Raku Programming Language:

    I've never heard the terms "early/late binding" used in this way. Generally it refers to how static (early) or dynamic (late) a language's symbol resolution and function dispatch mechanism is.

    They're related. Binding is actually the part where a symbol's name in a particular use is coupled to its meaning in that use. The symbol might be naming a function or a variable or a constant or a type or whatever. In C, the lookup is done immediately by the compiler during parsing of the code (early binding).

    For C specifically, that's a hack required by a grammatical ambiguity. (Do you parse A * b as a multiplication expression or a pointer-typed variable declaration?) Most other languages don't suffer from this issue, but there are plenty that bind early because it just makes for a better language.

    In other bad languages, the lookup is done at the time of use (late binding).

    🔧 The more complexity of programs rises, the more we rely on good tooling to help us build them correctly, which late binding interferes with. It was a bad concept, and I wish Lisp had never invented it and infected the rest of the world with it.

    In simultaneous binding, all symbols in the language are conceptually declared at the same time; that's great except for the cases where it isn't true and then you're into proper 🤯 territory.

    Can you elaborate on this? I'm trying to think of examples of where this happens in C# and drawing a blank. Generally speaking, when you need something to have been declared earlier, you move it to a dependent assembly, and then it was not "conceptually declared at the same time" as the symbols in your current project.

    Actual function dispatch is something else, and always post-binding. The dispatch phase itself requires the implementation of the thing which is being dispatched to.

    Yeah, you're the first person I've heard discuss dispatch as something distinct from binding. The standard perspective seems to be the one offered in *googles up a random example* this article, which explicitly describes virtual function dispatch in C++ as "late binding", even though the symbol lookup and resolution of calls (to a vtable slot) has already been done by the compiler.


  • Discourse touched me in a no-no place

    @Mason_Wheeler said in The Raku Programming Language:

    Can you elaborate on this? I'm trying to think of examples of where this happens in C# and drawing a blank. Generally speaking, when you need something to have been declared earlier, you move it to a dependent assembly, and then it was not "conceptually declared at the same time" as the symbols in your current project.

    That's the exception to the simultaneous declaration rule.



  • @dkf And how does that "lead to 🤯 territory"?


  • Discourse touched me in a no-no place

    @Mason_Wheeler I think I was thinking about the fairly complex rules for value initialisation. I can't be sure though; I didn't bother to remember exactly what I was think of, after all.



  • @dkf A lot of the weirdness and complexity there comes from lazy initialization at runtime, rather than the compiler's binding strategy. This is something I've had plenty of :headdesk:s about, going over it with .NET team members. They've got this bizarre brain worm going about how lazy initialization is this awesome thing that everyone loves, even though it demonstrably adds lots of headaches and overhead to the system. Lazy initialization is a useful tool to use as appropriate, but a bad default and a terrible only option.


  • Considered Harmful

    @dkf In Raku, however, 'binding' means something convoluted involving 'containers', which are something convoluted. The upshot is you can say

    my $x = 5;
    my $y := $x;
    $y++;
    

    and have $x be 6. And it works for every value in every context. For example, to update a list:

    for @list <=> $x {
        $x++;
    }
    

    Of course this is much more clearly written as @list»++, but it gets the point across.


  • Considered Harmful

    @Mason_Wheeler In Raku the rules for this are simple. Just wrap it in INIT { } and it's before everything else.


  • BINNED

    @pie_flavor said in The Raku Programming Language:

    @dkf In Raku, however, 'binding' means something convoluted involving 'containers', which are something convoluted. The upshot is you can say

    my $x = 5;
    my $y := $x;
    $y++;
    

    and have $x be 6. And it works for every value in every context. For example, to update a list:

    for @list <=> $x {
        $x++;
    }
    

    Of course this is much more clearly written as @list»++, but it gets the point across.

    Perl calls that aliasing, which of course you need a module for:



  • @pie_flavor said in The Raku Programming Language:

    @Mason_Wheeler In Raku the rules for this are simple. Just wrap it in INIT { } and it's before everything else.

    Wow, something this bizarre language actually got right!

    So how does it resolve initialization order, in case one thing needs to INIT before another?


  • Considered Harmful

    @Mason_Wheeler Single-pass with no circles, remember? What's before in resolution order is before in runtime order.
    Anyway, you can read more about things like INIT in this post.


  • Considered Harmful

    I have been enlightened. Disregard all previous content about Int:U and typeof, especially the bit about calling C.
    See, when you define a class, the name of that class now refers to a type object, which I previously thought roughly meant typeof(int) in C#. But this assumes Raku's object-model is like C#'s, and boy is it not. If I use Int's type object, the reason that passes a type-check for Int is because it is an Int. Just an undefined one. It is like a typed null, a null that can only be used where a nullable Int is required and not where a nullable, say, Str is. Then when you call bless, it makes an object just like the undefined one, except defined, and then starts the construction process. This makes the :D and :U syntax much clearer: Int:D takes defined Ints, and Int:U takes undefined Ints.


  • Considered Harmful

    Some things that look like methods are actually keywords. This is fine. What's not fine is getting no error when you define a method with the same name, and getting no warning when you call it.

    class A {
        method WHAT { "ain't gonna happen" }
    };
     
    say A.new.WHAT;    # OUTPUT: «(A)␤» 
    say A.new."WHAT"() # OUTPUT: «ain't gonna happen␤» 
    


  • @pie_flavor said in The Raku Programming Language:

    Some things that look like methods are actually keywords. This is fine. What's not fine is getting no error when you define a method with the same name, and getting no warning when you call it.

    class A {
        method WHAT { "ain't gonna happen" }
    };
     
    say A.new.WHAT;    # OUTPUT: «(A)␤» 
    say A.new."WHAT"() # OUTPUT: «ain't gonna happen␤» 
    

    Except that if they were really keywords, the precompiler would barf up jolly error messages when it encountered the definition of method WHAT. As it is, they are in a sort of half-and-half neither-one-thing-nor-another Limbo state.


  • Considered Harmful

    A junction is a logical superposition of values. For example, 1|2|3 is simultaneously any of the values 1, 2, and 3 (also constructible with lists, like any 1, 2, 3). There's any / | for logical-or junctions, all / & for logical-and junctions, and one / ^ for logical-xor junctions.

    A junction has two magical properties. First, if you evaluate it in a boolean context, it evaluates all its elements in a boolean context, and collapses to a single boolean value according to its logical operation. Second, any function existing on a junction's elements, automatically exists on a junction, and forwards it along, changing signatures as necessary. For example, given sub convert-to-english(Int $x --> Str), despite taking specifically Int and not Junction, you can call convert-to-english(5|6) and get 「five」|「six」. You might check if 5 is contained within the range [3, 8) with if 5 ~~ 3..^8, but you could just as easily say if 5 == any 3..^8, despite infix:<==> only existing between numerics, not junctions.



  • @pie_flavor said in The Raku Programming Language:

    A junction is ...

    I actually kind of like that, although who knows if it's at all performant for anything half way complicated.


  • Java Dev

    @bobjanova Looks like it basically means that if you have Junction<String> names and you write strlen(names) it is transparently converted to names.map(s => strlen(s))


  • Discourse touched me in a no-no place

    @PleegWat That, or the potential to generate it. That'd be neat.



  • @Steve_The_Cynic said in The Raku Programming Language:

    @pie_flavor said in The Raku Programming Language:

    Some things that look like methods are actually keywords. This is fine. What's not fine is getting no error when you define a method with the same name, and getting no warning when you call it.

    class A {
        method WHAT { "ain't gonna happen" }
    };
     
    say A.new.WHAT;    # OUTPUT: «(A)␤» 
    say A.new."WHAT"() # OUTPUT: «ain't gonna happen␤» 
    

    Except that if they were really keywords, the precompiler would barf up jolly error messages when it encountered the definition of method WHAT. As it is, they are in a sort of half-and-half neither-one-thing-nor-another Limbo state.

    That's actually pretty normal. Many languages use "contextual keywords" that are valid identifiers, but have special meaning in some places.


  • Considered Harmful

    @bobjanova said in The Raku Programming Language:

    @pie_flavor said in The Raku Programming Language:

    A junction is ...

    I actually kind of like that, although who knows if it's at all performant for anything half way complicated.

    The docs say:

    Rakudo has been developed with the philosophy of "make it work right then make it work fast."

    Unsure which step they're on.


  • Discourse touched me in a no-no place

    @pie_flavor said in The Raku Programming Language:

    Unsure which step they're on.

    Somewhere between “make it” and “work right”?



  • @pie_flavor said in The Raku Programming Language:

    I have been enlightened.

    a0390bf5-3776-4f5a-bcf0-abef1fb1af23-image.png

    For some reason Google cannot find the actual original strip in English, even though it can find it in French and shows many closely related strips from the same story in English... so you get the translation with a different drawing as a bonus:

    d7002e1b-b990-4f83-92bb-43eed53698d4-image.png


Log in to reply