|
| hprotagonist wrote:
| "and behind every framework, there's a langauge trying to get
| out, to protect semantic ideas, then semantic ones, and _then_
| support the logical ideas that we have " -- Lambda World 2019 -
| Language-Oriented Programming with Racket - Matthias Felleisen
|
| https://youtu.be/z8Pz4bJV3Tk?t=180
| TazeTSchnitzel wrote:
| Rust's traits let you add methods like this to any type without
| creating a risk of conflicts, because they aren't accessible
| within a particular file unless you import the trait. (Also I
| think there's some syntax for disambiguating?)
| remram wrote:
| The syntax is function-style, e.g. `Trait::method(object)`
| rather than ` use Trait; object. method()`
|
| Or you can cast &object to &Trait.
| overgard wrote:
| So like, I guess the thing I don't understand is this: why do
| people think writing:
|
| some_array.has_my_thing() is better than
| has_my_thing(some_array). ?
|
| The former, the extension has so many issues, it messes up
| namespacing, it's unclear where it came from, etc. etc. The
| latter is just a function. It's not longer, or complex, it's just
| more straightforward. I really think things where you extend or
| override built in types is almost always just a bad idea, because
| the alternative is almost always just as concise and doesn't
| confuse everyone.
| RangerScience wrote:
| In your example, `has_my_thing` then has to be able to handle
| any possible input (even if it's just to say "I can't handle
| this input). Example: length of objects/hashes, and length of
| arrays.
|
| And, sure, I guess you _could_
| `Array.has_my_thing(some_array)`... but that 's just re-
| arranging the mixin structure behind `Array`. It only looks
| different until you start peaking under the hood.
|
| IMHO, sometimes you want a function because in your problem
| domain there's a universal (or universal enough)
| act/question/etc, and sometimes you want a member function
| because in your problem domain the act/question/etc only makes
| sense given some particular context.
| fernandotakai wrote:
| >some_array.has_my_thing() is better than
| has_my_thing(some_array). ?
|
| one of the reasons i prefer python to ruby. sorted(my_thing)
| will sort anything that can be sorted. no need for monkey
| patching -- you just call it and, if it can be sorted, it will
| be sorted.
| runevault wrote:
| Did they ever fix the arbitrary nature of monkey patching
| where last in wins? I've not touched ruby in years (and never
| seriously after I read up on how prevalent MP was).
| RangerScience wrote:
| Sort of. They introduced "refinements" as the thing you're
| supposed to do instead of monkeypatching, but AFAIK it
| doesn't get wide-spread usage.
|
| IME you don't usually do monkey-patching, although there
| are circumstances where it makes A LOT of sense (usually
| test suites). It's one of those sharp knives - safe if you
| plan out using it, dangerous if you don't.
| jacobsenscott wrote:
| Yes, they added refinements several years ago. That said
| I've been programming rails for probably 10 years, and I
| never see anyone use refinements, and I can count on one
| hand the number of times monkey patching has actually been
| a problem for me personally. I'm sure there are cases where
| it bit someone hard, but this is one of those things that a
| theoretically bad, but never seem to really have any impact
| in practice.
| matheusmoreira wrote:
| In Ruby, anything that can be sorted will respond to sort. So
| thing.sort will also sort anything that can be sorted.
|
| Python does the exact same thing, it just hides it from you
| using ugly __methods__ that the language itself will call by
| convention. What determines sortability? "Anything that can
| be sorted" just means anything that implements the __lt__
| method. In Ruby, this method is called <=> and the Comparable
| module builds upon it.
| remram wrote:
| Nothing like sort is hidden in class methods in Python.
| johnmaguire wrote:
| That's not true - Python implements sorted by calling
| `__lt__` on the object:
| https://docs.python.org/3/library/functions.html#sorted
| Mikeb85 wrote:
| > So like, I guess the thing I don't understand is this: why do
| people think writing: > some_array.has_my_thing() is better
| than has_my_thing(some_array). ?
|
| The latter is in the global namespace (or you have to create a
| module/namespace for it). The former is encapsulated in a
| class. Encapsulation is nice.
| zer0-c00l wrote:
| Except here the encapsulation comes at the cost of extending
| a core library at runtime, which has all the tradeoffs
| mentioned in the article.
| jshen wrote:
| One benefit is discoverability. I coded a ton of Ruby/rails
| back in the day and it was nice to be able to jump into a
| repl and see what methods were on an object. Also, you
| could often find the source of the method through the repl.
|
| I think a lot of these debates come down to repl
| development versus ide development. I've done a lot of
| both, but many complaints come down to people on one side
| not understanding the way the other side works.
| matsemann wrote:
| In other languages (like Kotlin), that extension is
| actually not done on the object, but is a statically
| imported function and it's only syntactic sugar. This
| avoids all the pit falls (no collision, knows where the
| function comes from etc)
| dgb23 wrote:
| The level of encapsulation seems to be the same. It's just a
| different notation in that case.
| manquer wrote:
| The first style is more aligned to how some people reason the
| statement in their mind and that is why they like it better.
| sparker72678 wrote:
| Personally, I just find `some_array.has_my_thing?(thing)` to be
| more readable, and I spend way more time reading code than
| writing it.
| ajmurmann wrote:
| I think this might be hosting complexity which reminds me a
| little of Rich Hickey's Simple Made Easy talk. The Rails way
| seems more readable because it's hiding complexity. The other
| approach reveals the complexity, but actually has less
| complexity than the Rails style solution. This might only
| become apparent when something goes wrong.
| ajmurmann wrote:
| I think you are right that the solution where you pass the
| array in is clearer and probably more maintainable. It doesn't
| seem object-oriented at all though. It also leads to a totally
| different look and feel between built-in and extensions. It's
| not idiomatic at all.
|
| So, I think it's fair to say that the advantages you are lay
| out are more tangible than the other side of the trade-off.
|
| Having written too much Ruby code I'd still cringe every time I
| have to pass the array.
|
| Edit: To make it actually clean it should be
| 'MyArrayLib.has_my_things(array)'. Still really dislike it
| despite all the logical arguments for it.
| TomVDB wrote:
| I'm switching back from Ruby to Python out of necessity, and I
| loath things like len(my_list) vs my_list.len().
|
| I just don't understand why Python thinks it necessary to
| define global functions for something that naturally should
| exist as a method.
|
| And, of course, there's no way to know up front when to use a
| global function vs when to use a method.
| RangerScience wrote:
| +1 on the unpredictability being an issue. "Only one right
| way to do", yeah... gimme that least surprise :)
| dfinninger wrote:
| len(my_list)
|
| is just sugar for my_list.__len__()
|
| if you feel strongly about the convention: https://docs.pytho
| n.org/3/reference/datamodel.html#object.__...
| mmahemoff wrote:
| Composability.
|
| some_array.do_thing().do_another_thing().do_something_else()
|
| versus
|
| do_something_else(do_another_thing(do_thing(some_array)))
|
| Note the first example could be an example of chaining - where
| each function returns "self" and we progressively transform the
| object. Or it could be simply each function returning different
| values which are operated on. Either way, the pattern is
| usually cleaner and easier to debug than the nested equivalent.
| choward wrote:
| So it's a purely a syntax issue? Other languages like elm
| have a cleaner syntax for that.
| empthought wrote:
| It's super ironic that you used the term "composability" and
| didn't actually use functional composition for the second
| example.
|
| (do_thing . do_another_thing . do_something_else) some_array
| funklute wrote:
| But this kind of functional composition often doesn't have
| first-class support in the language syntax. That is, it
| often requires you to rely on helper functions or
| libraries. As a result, it's not nearly as readable or
| intuitively obvious as the chaining example (and this is in
| contrast to mathematical notation, where functional
| composition is very clear, in my opinion).
| timr wrote:
| You don't need to implement chaining for X.foo() to make
| sense. It's object-oriented syntax. If anything, languages
| like Python are the odd ducks here, mixing magical globals
| (len(X) => X.__len__()) with plain-old OO syntax conventions.
|
| That Ruby _also_ implements X.foo().bar().baz() is a weird
| thing about Ruby that can be very powerful, but is unrelated
| to the dot syntax.
|
| I feel like roughly half of Ruby programmers treat it as
| "Lisp but better", which leads to confusion about the OO
| aspects of the language.
| jonnycat wrote:
| Elixir (and some other languages as well) solves this with
| the pipe operator:
|
| some_array |> do_thing() |> do_another_thing() |>
| do_something_else()
|
| Even though Elixir is functional and aggressively not object
| oriented, if you squint at this pattern you get the
| readability of an OO-style method chaining API.
| [deleted]
| bryanrasmussen wrote:
| I'm pretty sure they're both equally composable as I
| understand the term for programming language usage, it's just
| that you prefer the first way of writing it.
|
| Admittedly I don't think anyone really prefers the second way
| of writing it, but that's not the same as being ecstatic over
| the first one.
| Twisol wrote:
| A now-deleted (v_v) comment rightly called out that in many
| languages, method-style invocations are inextensible: a fixed
| set of methods exists when the class is created, and you
| can't any more after the fact. So at some level you're
| _forced_ to switch to direct-style invocations, and mixing
| the two can become ugly.
|
| Some languages (like C# and Rust) support extension methods,
| so you _can_ use method-style to invoke separately-defined
| procedures. But in other languages, method-style APIs become
| an inextensible privileged zone, and I personally prefer to
| minimize the number of inherent methods as much as possible.
| By preferring direct-style invocations, I avoid the
| temptation to stick a useful method on the class itself "for
| convenience".
| servytor wrote:
| Because intellisense can help.
| geysersam wrote:
| That makes sense. This is the most convincing reason I've
| come across in this thread.
|
| How do code completion work in languages where the predicate
| goes before the subject?
| sobellian wrote:
| Subjectively, the chief advantage is readability for long
| chains of function composition. Compare
| list.fft.map(square).sum.sqrt to sqrt(sum(map(fft(list),
| square))). This is all a matter of taste, but IMO the former
| reads more easily.
|
| It's a pretty trivial matter, so I wouldn't go breaking
| encapsulation everywhere just to support it. D has a feature
| called Universal Function Call Syntax where a.f(b, c) is sugar
| for f(a, b, c) for any free function, rendering those issues
| moot. I just wish more languages would pick it up!
| spyckie2 wrote:
| I think this is the beauty of Ruby. The core philosophy of Ruby
| is that it was designed to make "1.day.ago" possible. That's why
| DHH fell in love with it and used it to build Rails. You can't do
| that with many other languages.
|
| "1.day.ago" is not really a piece of code, it's a sensibly named
| shortcut to existing code that already solves easy problems. It's
| is not designed to be built upon; not all code has to be designed
| that way.
|
| For example:
|
| // How to get last day of month?
|
| // Javascript
|
| var month = 0; // January
|
| var d = new Date(2008, month + 1, 0);
|
| console.log(d.toString()); // last day in January
|
| // monkey patching in ActiveSupport
|
| Date.today.end_of_month
|
| This is the definition of a great DSL. It abstracts away easy
| problems so you don't have to solve them hundreds of times and
| allows you to focus on the more unique problems of a domain.
|
| Monkey patching is a powerful tool and just like any powerful
| tool it should be used carefully. Random monkey patching
| everywhere is bad, just like polluting the global namespace in
| javascript is bad. But used well and you can create extremely
| expressive, powerful, and concise coding experiences. Isn't that
| the goal of any DSL?
| matsemann wrote:
| Think that should be possible in Kotlin as well, fwiw.
| Extension functions and extension properties are nice. And
| function with receivers make for some nice DSLs. All without
| monkey patching, which I consider a better way.
| sparker72678 wrote:
| ActiveSupport is one of my very favorite things in the Ruby
| ecosystem.
|
| I can understand why it might not be to someone's taste, but I
| find the idioms to be generally delightful to use and, in most
| cases, extraordinarily convenient.
|
| But, as always in the Ruby ecosystem, if you don't like it, find
| the thing that brings you joy!
| ativzzz wrote:
| I think the author's example of time_calc compared to
| ActiveSupport's 1.days.ago syntax speaks to why ActiveSupport is
| used so much and that sometimes it's OK to do the wrong thing to
| make everything else easier. The time_calc API looks just awful
| to use I'd rather deal with the implications of potential Ruby
| "magic".
| mmahemoff wrote:
| You can make that argument if you consider a language is more
| than just syntax. It's an complicated ecosystem, of tooling
| (compilers, runtimes, repls, IDEs, debuggers), reusable code
| (libraries, frameworks), conventions (coding styles, idioms,
| design patterns), and community.
|
| I'm not really fussed about dictionary definition debates anyway.
| I generally use ActiveSupport in personal Ruby projects. It just
| adds too much value to ignore.
| RangerScience wrote:
| > RSpec is our primary example here - a limited and problematic
| DSL based on monkey-patching was turned into a beautiful,
| composable DSL which we still have in RSpec.
|
| One of my most consistent experiences with Ruby is doing
| something the "wrong way" - but being _able_ to do, due the
| language flexibility - and then later coming back to the problem
| and realizing the better solution, which ends up being more
| satisfactory and happier in every way.
|
| Ruby lets you do whatever you want, however you want, but it
| makes the _right_ way the most satisfying. Very handy for
| iterative development.
| byroot wrote:
| I think "Jargon" would probably have been a much less
| controversial term than "Dialect" for expressing this idea.
|
| "Dialect" implies that it's a sub-language, but Ruby is still
| Ruby no matter how many methods you add or modify.
|
| Whereas a "Jargon" is a specialized vocabulary, and even
| sometimes some word change meaning as part of a jargon.
|
| But I suppose that when you title your post like this,
| controversy is actually what you are looking for.
| ecf wrote:
| Clickbait title
| anandvc wrote:
| ActiveSupport is a core part of Rails though.
| steve_adams_86 wrote:
| I think this is the author's take on that:
| https://solnic.codes/2022/02/02/rails-is-not-written-in-ruby...
|
| Not sure this is what you're getting at. I agree with the
| author though, this aspect of Rails bothered me quite a bit.
| Knowing that working on a Rails project meant I could magically
| generate ranges from dates because of ActiveSupport was
| unsettling - it made me wonder what else was non-native
| behaviour and waiting to trip me.
| jon-wood wrote:
| I just can't bring myself to get worked up about it - I've
| done a lot of Rails, and I've done a lot of pure Ruby. You
| quite quickly learn which bits come from ActiveSupport when
| you step outside Rails because... it doesn't work. It's not
| going to trip you up in 8 month's time after shipping your
| code, you're just going to get an exception when you first
| try to run it, and then either implement it the pure way or
| add a dependency on ActiveSupport.
| manquer wrote:
| Prototype modification of global objects in JS provides similar
| monkey patching capability. Interestingly evolution is very
| different though
|
| The instances of abuse are generally less in mainstream JS
| libraries, and in many of them such features are usually opt-in
| or at-least it is possible to still use the lib even when opting
| out , there is also no major dialect that has privileged rights
| so to speak.
| choward wrote:
| The Prototype js library was pretty huge back in the day when
| monkey patching was all the rage.
| hihihihi1234 wrote:
| As a former Rails dev, I've always enjoyed Piotr Solnica's
| writing. He does a great job of explaining what's wrong with the
| framework, in particular the flaws that aren't immediately
| obvious when you're starting out.
|
| But these days the main thing I think of when I hear his name is
| that his blog used to be on a different domain, and he apparently
| let the old registration expire because someone else has bought
| it and now it points to a porn site. And tragically, there are
| still many other sites online which still link to Solnica's
| outdated, now-pornographic URLs.
|
| And that's how I ended up accidentally sharing a porn link in a
| professional setting.
| widdershins wrote:
| Somehow this story seems to relate to the author's musings on
| conflicting monkey-patched libraries. It's all rather
| beautifully messy.
| temac wrote:
| And programs written in Lisp are not written in Lisp?
| jaredcwhite wrote:
| I understand that if you like Ruby a whole lot and like being a
| web developer, but you _don 't_ like Rails for whatever reasons,
| it can be a frustrating experience over the long haul.
|
| But as a counter-example to that, I'm constantly amazed that
| there _are_ a ton of Ruby gems out there which pretty much work
| as advertised outside of Rails (even if Rails gets a privileged
| happy path during config). Not to mention you can use ecosystem
| stalwarts like Puma, Rack, Sidekiq, and many other subsystems
| outside of a Rails app entirely. Heck, you can pull just bits of
| Rails in if you really need them. Want Active Record for your ORM
| but nothing else? That 's totally possible! (But of course then
| you get a bunch of Active Support stuff too which is what the
| author objects to.)
|
| Personally I _love_ Active Support and actively (heh) bring it
| into my Ruby projects if it 's not there already. To a certain
| degree, everything people say is a "bug" about Ruby's
| metaprogramming/monkeypatching is a feature in my book. The fact
| that "Ruby core" is simply a substrate upon which you can build
| your own flavor of a Ruby-plus language--be that "The Rails Way"
| or something else entirely--is amazing. In that respect, I
| entirely disagree that Rails is not written in Ruby. Rails shows
| us how you _can_ (and probably should!) use Ruby to build DSLs
| which suit your specific application/framework purposes very
| well. It's not a bug. It's a feature. And it's why most other
| tools which claim "Rails but for Language X" fall short...they
| can try to replicate features of Rails, sure--but because it's
| not Ruby, it misses the whole point of using Rails, which is that
| you get Ruby "for free" to sweeten the deal! That's the (not so)
| secret sauce here.
___________________________________________________________________
(page generated 2022-02-04 23:00 UTC) |