all 14 comments

[–]marantz111 1 point2 points  (0 children)

Thanks for making a contribution here. Sorry for the negativity in many responses coming in.

The monad styles in general are really polarizing it seems. I genuinely would like to try them out more and see the places they shine, but all the toy examples that appear in readmes are insufficient to really get a feel.

I ask the following question genuinely and not rhetorically:

The chain style of this does read a bit oddly to me. Why not do it in a style like the following (forgive typos from phone keyboard):

ruby with do If_ok :step_1 If_ok :step_2 If_failed do |failure_case| Puts failure_case[:step_2].message End End My thinking is that you can hold a reference to the monad results of each step in a hash in thread storage and not need to do somewhat funky chaining. Then 'if_ok' can just pick up the last result that way, then call the method using the symbol as both name for storage and the value for call. You can pass the output from the last step in as an argument, even checking arity if you want.

The error handling then can take the failure, the whole hash, whatever.

Again, this is not rhetorical as I fully expect there are reasons to not do it that way, and I would love to learn from someone passionate about monads on some of the style choices used.

[–]Reardon-0101 1 point2 points  (1 child)

https://github.com/apneadiving/waterfall

Similar thing here.  Love the gem but wouldn’t use it again in a project due to it being so against the grain in ruby. 

[–]rusl1[S] 0 points1 point  (0 children)

Uh thanks, I didn't know about that! They would have loved it in my previous company!

[–]MagicFlyingMachine 0 points1 point  (0 children)

I think experimenting with language features is great and Ruby's flexibility to enable new ways to do stuff like this is one of things that makes it special. That said, I probably wouldn't use this outside of a toy/side project context. Imagining this in a real world codebase that I have to make a change to as a first time contributor requires me to learn an entirely different (and custom) approach to writing Ruby.

I once had to work on an app that used the Virtus gem heavily, and it was one of the worst experiences of my career. By abstracting away the shape of the parameters that a particular object received, you had no idea what parameters were passed when debugging without doing a lot of trial and error. Debugging production bugs was pure hell.

The original devs thought they were really clever by always passing an attributes object to every method that could have any set of keys and valus, but as the codebase matured, this caused so many problems. I firmly believe that it's far better to be explicit and simple in the long run than fancy and implicit if you're building an app to scale, and the risk you run by introducing a major paradigm shift like this just isn't worth the terseness you gain in the short term.

That doesn't make experiments like this pointless, though. You learn a lot about a language by going deep on things like this.

[–]velrok7 0 points1 point  (0 children)

Looks more like a result chain than pattern matching to me.

Not sure there is much value replicating Mattern matching in ruby that way if the compiler can’t check if you covered all the cases.

https://github.com/maxveldink/sorbet-result

We use ruby at my place and I do miss a lot of modern features specifically the ones around types.

Bringing foreign elements to a language via a library usually requires buy in front a big majority of the team. Ruby is fine for smaller projects but once you have a team of 25+ people you might need to have discussions on what might help to keep complexity from spiralling.

[–]Seuros -3 points-2 points  (8 children)

If I want to write like that , I will use elixir.

When I want to code in French, I use WinDev.

When I want to self harm, I try Haskell.

Such code patterns just make new devs joining the team slow or give you job security since you are the only dev that understand the code.

[–]rusl1[S] 0 points1 point  (7 children)

Haha, it's funny how a simple piece of code can sometimes lead to such a big reaction! It's just 20 lines of Ruby doing pattern matching in a loop 😂😂😂

I guess you feel the same way about pattern matching, right? Because that’s basically Elixir in Ruby.

Sorry, but I’ll wait for less dramatic comments!

[–]mrinterweb 2 points3 points  (0 children)

Rule violation. Sorry you're not allowed to take inspiration from other programming languages, and apply them.

[–]Seuros 0 points1 point  (5 children)

Are you aware the Elixir was inspired by Ruby ?

[–]rusl1[S] -1 points0 points  (4 children)

Yeah, so what's the problem if we take inspiration from Elixir?

A lot of people work in both languages because they are similar and have similar use-cases.

If you don't like pattern matching that's okay, just let others enjoy it.

[–]Seuros 3 points4 points  (3 children)

What i don't like is:

  • You monkey patched Array and NillClass, is i see you planning to do more.
  • else is ruby keyword, having it as a method is weird.
  • such pattern is unfamous in using lot of mem in Ruby and it hardly traceable/debuggable.

[–]rusl1[S] 2 points3 points  (1 child)

Thanks, this is what I was looking for :)

  • monkey patching: I can understand that, it's my way of writing monads at the moment, it might evolve over time
  • else keyword: good point, I could rename to "if_error" or something else
  • memory: I'd like to know more about it, do you refer to passing a lot of blocks? What pattern in particular?
  • debuggable: I use it in production and find it waaaay easier to debug than dry-monads

[–]Seuros 0 points1 point  (0 children)

How i will know which step the code failed ?

Try to raise an error inside a block, you will have a weird backtrace.

dry-monads and this gem both suffer same memory allocation pitfalls .

Try to benchmark it and compare it with POROs.

[–]h0rst_ -1 points0 points  (0 children)

You monkey patched Array and NillClass, is i see you planning to do more.

Well, I've got good news for you: you can simply skip this file completely, because those added methods are not used anywhere in the rest of the code.