Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Wow. Sign me up for leaving the industry before I ever have to maintain a Raku codebase.


Funny, cause reading that blog post made me want to quit my job and find a raku team to work with. Maybe I'm still too naive :)


Same. And it's a bit funny because I'm usually against unnecessary complexity, and here's a language that seems to have embraced it and become a giant castle of language features that I could spend weeks studying.

Maybe it's because Raku's features were actually well thought-out, unlike the incidental "doesn't actually buy me anything, just makes the code hard to deal with" complexity I have to deal at work day in and day out.

Maybe if Java had a few of these features back in the day people wouldn't've felt the need to construct these monstrous annotation soup frameworks in it.


Java inspired the Design Patterns book.

Every Design Pattern is a workaround for a missing feature. What that missing feature is, isn't always obvious.

For example the Singleton Design Pattern is a workaround for missing globals or dynamic variables. (A dynamic variable is sort of like a global where you get to have your own dynamic version of it.)

If Raku has a missing feature, you can add it by creating a module that modifies the compiler to support that feature. In many cases you don't even need to go that far.

Of course there are far fewer missing features in Raku than Java.

If you ever needed a Singleton in Raku (which you won't) you can do something like this:

  role Singleton {
    method new (|) {
      once callsame
    }
  }

  class Foo does Singleton {
    has $.n is required
  }

  say Foo.new( n => 1 ).n;
  say Foo.new( n => 2 ).n;
That prints `1` twice.

The way it works is that the `new` method in Singleton always gets called because it is very generic as it has a signature of `:(|)`. It then calls the `new` method in the base class above `Foo` (`callsame` "calls" the next candidate using the "same" arguments). The result then gets cached by the `once` statement.

There are actually a few limitations to doing it this way. For one, you can't create a `new` method in the actual class, or any subclasses. (Not that you need to anyway.) It also may not interact properly with other roles. There are a variety of other esoteric limitations. Of course none of that really matters because you would never actually need, or want to use it anyway.

Note that `once` basically stores its value in the next outer frame. If that outer frame gets re-entered it will run again. (It won't in this example as the block associated with Foo only gets entered into once.) Some people expect `once` to run only once ever. If it did that you wouldn't be able to reuse `Singleton` in any other class.

What I find funny is that while Java needs this Design Pattern, it is easier to make in Raku, and Raku doesn't need it anyway.


If you mean Design Patterns: Elements of Reusable OO software by Gamma et al, it was published in 1994. Java came out in 1995.

The Patterns book was originally a C++ text.

All programming languages have design patterns, they aren’t patterns as in “templates you should follow”, they are patterns as in “concepts you will see frequently for solving classes of problems”.

The Design Patterns book was a bestiary not a guide to replacement features.


Java does have a particular blend of features and lack of features that has led to the bloated, boilerplate-laden, inflationary framework ecosystem around it that is worse that I've seen in any other language.

Lack of stack-allocated structs leads to object pooling.

Lack of named arguments combined with the tediousness of writing `this.x = x` over and over, along with the reflection system that Java does provide leads to IoT frameworks that muck about in your private variables and/or generate objects "for you"[1].

Lack of a way to mark object trees as immutable short of duplicating all the constituent classes leads to everyone generally assuming that everything is and moreover should be mutable, necessitating complex systems for isolating changes to object graphs (e.g. the way Hibernate supports transactions).

Etc, etc. I wrote a list of these things somewhere.

[1] "It does X for you" is a phrase I've heard too many times from coworkers trying to sell me on some framework that we didn't need. "Oh yeah, it does an easy job for me an in exchange I have an incomprehensible spaghetti mess to deal with, thanks." Being the only person in the room who notices the complexity monster growing bigger and bigger is a never-ending source of frustration.

Record classes alleviate the pain of writing immutable data object classes but are unfortunately late to the party.


I'm not so sure every design pattern corresponds to a missing feature. For example, what feature would the Observer design pattern correspond to?


The feature that Observer would correspond to is simply Observers. Some of the patterns may happen to correspond to different names, but they don't all need different names or weird mappings, many of them are just "and now it's a feature instead of a set of classes".

That said, while the point "a design pattern is a feature missing from a language" has some validity on its own terms, the implied "and therefore a language is deficient if it has design patterns because those could be features" is nonsense. A language has some set of features. These features have an exponential combination of possibilities, and a smaller, but still exponential, set of those are useful. For every feature one lifts from "design pattern" and tries to put into the language, all that happens is an exponential number of other "features" are now closer to hand and are now "design patterns". This process does not end, and this process does not even complete enumerating all the possible useful patterns before the language has passed all human ability to understand it... or implement it.

Moreover, the argument that "all design patterns should be lifted to features" ignores the fact that features carry costs. Many kinds of costs. And those costs generally increase the cost of all the features around them. The costs become overwhelming.


"Design patterns are really Band-Aids for missing language features" comes from a 1996 Peter Norvig presentation[0][1]:

> Some suggest that design patterns may be a sign that features are missing in a given programming language (Java or C++ for instance). Peter Norvig demonstrates that 16 out of the 23 patterns in the Design Patterns book (which is primarily focused on C++) are simplified or eliminated (via direct language support) in Lisp or Dylan.

[0]: https://en.wikipedia.org/wiki/Software_design_pattern#Critic...

[1]: slide 9 of PDF https://www.norvig.com/design-patterns/design-patterns.pdf


In a language with a sufficiently expressive object system or other features such as macros we could turn the Observer pattern into a library. To get objects to participate in the pattern we then just somehow declare that they are observers or subjects. Then they are endowed with all the right methods. Simple inheritance might be used, but if your Observer or Subject are already derived then you need multiple inheritance to inject the pattern to them. Or some other way of injecting that isn't inheritance. In C++, the CRTP might be used.

Language features don't necessarily make the design pattern's concept go away, just the laborious coding pattern that must be executed to instantiate the pattern.

Writing a design pattern by hand is like writing a control flow pattern by hand in a machine language. When you work in assembly language on some routine, you may have the concept of a while loop in your head. That's your design pattern for the loop. The way you work the while loop pattern into code is that you write testing and branching instructions to explicit labels, in a particular, recognizable arrangement. A macro assembler could give you something more like an actual while loop and of course higher level languages give it to you. The concept doesn't go away just the coding pattern.

The meaning of "pattern" in the GoF book refers not only to concepts like having objects observe each other, but also refers to the programmer having to act as a human compiler for translating the concept into code by following a detailed recipe.

Because GoF design patterns are all object-based, they're able to use naming for all the key parts coming from the recipe. When you read code based on one of these patterns, the main reason why you can see the pattern is that it uses the naming from the book. If you change your naming, it's a lot harder to recognize the code as being an instance of a pattern.


events/reactive programming?


and further down the research path, chemical programming (forgot the name of the languages)


What captures my mind is a little blend of radical language design that I only find in Haskell for instance, without the type theoretic bagage, and a bit of 'thats just a fun perl idiom' when you used to hack around your old linux box.


I think it has to do more with familiarity than complexity. You could have a good understanding of features like the ones showcased in the blogpost, but it could take you a minute of staring at a line to parse it if someone uses it in a way you're unfamiliar with. Doing that for potentially hours on end would be a pain.

It's definitely something I'd write for fun/personal projects but can't imagine working with other people in. On a side note, I believe this is where go's philosophy of having a dead simple single way of doing things is effective for working with large teams.


Some of them seem ok, e.g. ignoring whitespaces in regex by default is a great move, and the `` as a shorthand single lambda argument is neat.

But trust me if you ever have to actually work* with them you will find yourself cursing whoever decided to riddle their code with <<+>>, or the person that decided `* + ` isn't the same as `2 *` (that parser must have been fun to write!)


yeah, you're right.

your entire comment is syntactically valid raku, or can be made so, because raku syntax is so powerful and flexible.

raku grammars ftw!

https://docs.raku.org/language/grammars

https://docs.raku.org/language/grammar_tutorial

;)

even that last little fella above, is or can be made syntactically valid.


That's a fair reaction to the post if you haven't looked at any normal Raku code.

If you look at any of the introductory Raku books, it seems a LOT like Python with a C-like syntax. By that I mean the syntax is more curly-brace oriented, but the ease of use and built-in data structures and OO features are all very high level stuff. I think if you know any other high level scripting language that you would find Raku pretty easy to read for comparable scripts. I find it pretty unlikely that the majority of people would use the really unusual stuff in normal every day code. Raku is more flexible (more than one way to do things), but it isn't arcane looking for the normal stuff I've seen. I hope that helps.


Sure, but the fact that weird stuff is possible means that someone, at some point, will try to use it in your codebase. This might be prevented if you have a strong code review culture, but if the lead dev in the project wants to use something unusual, chances are no one will stop them. And once you start...


If you suggest a language here where nothing weird can be done, I bet someone will reply with something weird done in that language.


This is true. I’ve written overly-clever, indecipherably dense code in many different languages. But some languages seem to practically encourage that kind of thing. Compare a random sampling of code from APL, Scala, Haskell, Perl, Clojure, C, and Go. You’ll probably find that average inscrutability varies widely between various language pairs.


Inscrutability to whom? I'm confident someone with 10 years of production Haskell experience will do a better job of reading production Haskell code than a comparable situation with C.

But then again, maybe that was what you were saying.


You say like you never looked at any Perl Golf solution.


Same as Perl, nobody wants to maintain it, but it's extremely fun to write. It has a lot of expression.

You can see that in Raku's ability to define keyword arguments with a shorthand (e.g. :global(:$g)' as well as assuming a value of 'True', so you can just call match(/foo/, :g) to get a global regex match). Perl has tons of this stuff too, all aimed at making the language quicker and more fun to write, but less readable for beginners.


Many of the features that make Perl harder to write cleanly have been improved in Raku.

Frankly I would absolutely love to maintain a Raku codebase.

I would also like to update a Perl codebase into being more maintainable. I'm not sure how much I would like to actually maintain a Perl codebase because I have been spoiled by Raku. So I also wouldn't like to maintain one in Java, Python, C/C++, D, Rust, Go, etc.

Imagine learning how to use both of your arms as if they were your dominant arm, and doing so simultaneously. Then imagine going back to only using one arm for most tasks. That's about how I feel about using languages other than Raku.


its not that reading perl is hard, the _intent_ of the operations of often hard/unclear.

Yes its nice to write dense fancy code, however, something very boring to write like PHP is a lot of "loop over this bucket and do something with the fish in the bucket, afterwards, take the bucket and throw it into the bucket pile" that mirrors a 'human follows these steps' type.


In the intent department, I have had more troubles with AbstractClassFactorySingletonDispatcher type Java code, add to that dependency injection magic/madness.

I'd rather maintain Perl any day than 30 classes of Java code just to build a string.


I once heard of a merger between a company that used Java, and another one that used Perl.

After that merger, both teams were required to make a similar change.

If I remember right, the Perl team was done before the Java team finished the design phase. Or something like that.

The best aspect of Java is that it is difficult to write extremely terrible code. The worst aspect is that it is difficult to write extremely awesome code. (If not impossible.)


If this was about my former $work:

The company using Perl was able to double its turnover in 3 weeks.

The company using Java was still in the design phase.

Companies choose their tools depending on their internal culture. The company using Perl at the time was simply more agile.

FWIW, the company that was using Perl is now using Java mostly. And yes, the culture of the company has changed. Not sure about cause and effect.


The thing is you can chose to write perl in a way that doesn't suck. The problem with TMTOWTDI is that with 18 people in a code base.... well its best to have a set of conventions when writing perl. Let's all agree to use 5.x.x with these features for example


These days you can TMTOWTDI in Python as well though.

The TMTOWTDI argument was valid in very early stages of Perl vs Python debate, like some what between 2000 - 2006 etc.

These days Python is just Perl with mandatory tab indentation. Python is no longer that small language, with small set of syntactical features. C++/Java etc in the meanwhile have gotten even more TMTOWTDI heavy over the years.


I don't really work with python often enough but as for php there's usually one boring way to do it. We eschew generally more fun stuff like array operations because for loops work and the intent is vlear


I’d rather have a compiler+ide-supported testing framework that doesn’t require a tested code to be prepared for being tested in any way. Almost all boring languages are fine at writing straightforward code without ceremony, even Java.


Good job those aren't the only two options!


Frankly I'm on Team Fish Bucket.

I am not totally convinced--well, not at all convinced, really-- that the OOP revolution made programming code better, simpler, easier to follow, than procedural code.

I suppose the argument ended up being a philosophical discussion about where State was held in a running program (hard to tell in procedural code, perhaps, and easier to tell in OOP), but after 20+ years of Java I wonder if baby hadnt disappeared down the plughole with the bathwater.


Perl reminds me of that job I had writing ANSI MUMPS.


it's extremely fun to write

Then your contrarian phase ends and you regret that you didn’t learn something useful in that time.


I was paid to write it, but still find it useful for short scripts and one liners. I'd use it over sed, awk or shell without pause.

It is very strong for text processing, particularly regexes.

Finally learning any language helps you learn new paradigms which you can apply anywhere. Same as Haskell or Lisp or something.


Things do not require to be useful or to increase revenue in order for them to be enjoyable. If the only reason you ever do something is because you get material wealth out of it, are you even making choices or are you a perfect rational actor as described in textbooks?

Things are allowed to exist and be enjoyed on the sole basis that they are enjoyable


Oh I’m not wealth motivated at all. My regrets are about uselessness of that time itself. E.g. I could learn ML instead and do nothing useful with it, rather than not doing nothing useful with my perl knowledge today.


This is so self-contradicting, it feels like division by zero


I could enjoy one knowledge today without having monetary interest in it ever, but instead I have another knowledge which is completely useless even for enjoyment.


the irony


Its strange that people are saying the same about maintaining code bases written using AI assistance.

Im guessing its going to be a generational thing now. A whole older generation of programmers will just find themselves out of place in what is like a normal work set up for the current generation.


I don't think Raku is intended for "the industry".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: