4 ms·
Ruby is really fun to program in, but debugging it can be hell. I would not be very enthusiastic about debugging this code. But still, this is a really cool tr
by TheAceOfHearts 11y ago
Ruby is really fun to program in, but debugging it can be hell. I would not be very enthusiastic about debugging this code.
But still, this is a really cool trick that I didn't know you could pull off with Ruby, so thanks for sharing!
- jamis 11y agoAgree about debugging. To my thinking, though, there are two types of "programming": professional (for day jobs, where debugging, testing, and maintainability matter), and recreational (where the point is to just explore new things and try crazy stuff that no one in their right mind would ever "really" do). This "def" stuff falls into the latter category. Honestly, I wish there were more people doing posts about recreational programming topics. WhyTheLuckyStiff was one of the last great recreational Rubyists. I miss that kind of no-holds-barred exploration.
- TeMPOraL 11y agoI don't see anything hard to debug in this code. Honestly, if this kind of code makes debugging hard for one it means that one assumes too much about how code should behave instead of looking how it actually behaves. I hate this "dynamic programming[0] = hard to debug" meme. A truly hard to debug code is one that's nonlocal (you have to read 20 files to follow the execution flow (hello Scala trait abusers)) or displays random behaviour (e.g. threading, dependence on external resources). This one? Every "tricky" thing is contained in a block of 10-20 lines. Just isolate the endpoints and follow the execution until it does something you think it shouldn't. In a way, the biggest enemy of a bug hunter is their own assumptions. [0] - examples here aren't really metaprogramming, and even the latter isn't that hard to debug if you actually sit down and read the code.
- deckard1 11y agoDebugging Ruby, in general, is often a pain in the ass. It stems from an awful combination of terseness and metaprogramming. The terseness comes from using an identifier to both represent variable reference and method invocation. Contrast this to Lisp-like langauges, where function (or macro) invocation only happens in the first position of an S-expression. In Lisp, it's clear that an identifier is either a variable or a function depending on where it's located. In Ruby, no visual indication exists. Worse, things like attr_reader blend instance variables with local variables and method identifiers. Throw in a method_missing and inheritance, and you can easily lose weeks just tracking down where an identifier is even coming from. Throw in a gem or two, and all hope is lost.
- TeMPOraL 11y ago> Contrast this to Lisp-like langauges, where function (or macro) invocation only happens in the first position of an S-expression. In Lisp, it's clear that an identifier is either a variable or a function depending on where it's located. It may not be depending on the context; consider: (let ((foo 123) (+ 'please-dont-do-that)) (print foo) (print +)) Both `foo' and `+' are variables here - while present on a first position of an S-expression at one point - even if you're running a Lisp-1 (like Scheme), i.e. where functions and variables share a namespace - or rather, a symbol can have separate function and value bindings. In Lisp-n (like Common Lisp) you can have a variable slot bound to a function value (i.e. lambda). But one thing Lisp does have, which impacts readability significantly IMO, is simple and consistent syntax. Contrast to some Ruby-like languages which let you skip braces when working with dictionaries, making you stop and wonder how the hell a given piece of code is going to be parsed by the interpreter. Or Scala, which has so much context-dependent meaning bound to non-letter characters that I finally start to understand why people were afraid of C++ operator overloading. Both examples are, in my opinion, cases of syntactic sugar leading to cancer of semicolon.
- deckard1 11y agoThe example you gave is clear, though. They are variables because they appear in a LET form. It's clear from the context what is going on. What I'm referring to, in Ruby, is something like: def some_method what_is_this end You don't know what what_is_this is. It could be an instance variable, a method (anywhere in the inheritance tower), or an autogenerated method from method_missing. It's impossible to tell without digging through the code. But the problem there is, you can't simply grep the code for things like this. You could end up with 100s of uses of the identifier and never find the source. Especially if you inherit a class from a gem, or method_missing has been used. > In Lisp-n (like Common Lisp) you can have a variable slot bound to a function value (i.e. lambda). Yes, and Lisp-1 vs Lisp-n has been a hot debate for decades in both Lisp and Scheme communities. I'm not about to claim it's a completely solved problem there.
- TeMPOraL 11y ago