ruby dataflow library
Pretty cool, I worry that such things can’t easily be done so cleanly in python…
Pretty cool, I worry that such things can’t easily be done so cleanly in python…
More and more, I am wishing that there was some sort of strict mode I could enable in ruby to say “you know what? I’m careful with my code. Please don’t assume things behind my back”. And to be honest, this mode would pretty much be synonymous with “just do what python would do”
By default, python is strict. If you index a dict (hash) with a nonexistant key, you get a keyError. If you don’t want to have to deal with that, you can use the get
method and provide a default for if the key doesn’t exist. In ruby, if you want to be strict about anything, you generally have to write your own checks to guard against the core library’s forgivingness. Forgivingness sounds nice at first, but goes completely against the idea of failing fast, and frequently delays the manifestation of bugs, making them that much harder to actually track down.
Two examples that I came across within minutes of each other the other day:
Struct.new(:a,:b,:c).new('a','b')
that should NOT go without an exception
"a|b||c".split("|")
=> ["a", "b", "", "c"]
good…. so now:
"a|b||".split("|")
=> ["a", "b"]
argh! what have you done to my third field?
Not a very exciting realisation, but an annoying one:
$ irb
>> class A
>> def self.meth; puts "class method!"; end
>> end
>> A.meth()
class method!
>> A.new().meth()
NoMethodError: undefined method `meth' for #<A:0x5ad160>
from (irb):11
ick…
(sadly enough, most of my posts tagged “ruby” would be equally well tagged as “things that suck in ruby”)
(if you don’t read my blog for the geeky thrill of it, you may want to give this post a miss ;))
Follow my little IRB session, if you will:
>> nil or "val"
=> "val"
>> puts (nil or "val").inspect
=> "val"
>> x = nil || "val"
=> "val"
>> x
=> "val"
>> y = nil or "val"
=> "val"
(wait for it…)
>> y
=> nil
Seriously, ruby. What the crap?
Okay, so I just figured out what’s going on here. “or” works both as a logic operator and a conditional statement. Just like you can do:
x = something_dangerous() rescue "x failed!"
and
puts "x is greater than 10" if x > 10
It would seem you can also do
x = some_value or puts "i guess the assignment didn't evaluate to true"
Meaning that in my example above:
y = nil or "val"
Ruby evaluates it as:
(y = nil) or ("val")
(i.e. in the second set of brackets, y is not actually assigned to anything)
Of course, ||
is solely a logic operator. Which is why it looks like you get different behaviour when you use ||
instead of or.
When I found out about ruby supporting both sets of logic operators (&&
, ||
, !
) and (and
, or
, not
), I thought it was dumb, but just a matter of preference which type you prefer.
When I found out that the symbol-based ones bind tighter than the keywords, I winced a little and noted to myself never to rely on that, because it’s neither readable or obvious.
Now that I’ve stumbled upon this latest gem of knowledge, It just makes me cringe…
Pay attention to the output types, kids:
>> { "key" => "val" }.reject { false }
=> {"key" => "val"}
looking good so far...
>> { "key" => "val" }.select { true }
=> [["key", "val"]]
eww... what?