Mailinglist Archive: yast-devel (127 mails)

< Previous Next >
Re: [yast-devel] Ruby 'next' considered dangerous
I forgot to mention two things...

1) it is not just "next", "break" is also affected. E.g. try using
break in reduce, it also produce nil. Or even more funny

irb(main):001:0> [0, 1, 2].map { |a| break 15 }
=> 15

2) recommended way at least in recent ruby is to use each_with_object
instead of reduce
( http://apidock.com/rails/Enumerable/each_with_object )
which do not use return value, but modify passed object.

Example code
irb(main):002:0> [0, 1, 2].each_with_object({}) { |a, res| a == 1 ? next :
res[a] = a.to_s }
=> {0=>"0", 2=>"2"}



On Wed, 18 Nov 2015 11:33:23 +0100
Josef Reidinger <jreidinger@xxxxxxx> wrote:

On Wed, 18 Nov 2015 10:13:45 +0100
Stefan Hundhammer <shundhammer@xxxxxxx> wrote:

On 18.11.2015 09:56, Josef Reidinger wrote:
And to be honest it can happen in any code in any language ( just
depending how often it can happen ).

Wrong.

Any halfway decent parser will realize that in one case you do
return something from your function, and in another you don't.
That's what happened here.

Preciselly speak you always return something. Just maybe default value
for return is not so common in other languages. I know that e.g. C++
can check it during compilation, but ruby is not compiled, so in the
end, you in both cases ends up with runtime error or error catched by
test suite.


Better yet, if you have to DECLARE your stuff (functions,
variables), you are making a commitment (or a contract, however you
want to name this) what you are going to do with that thing and
what you don't. And the parser (no matter if it's an interpreter or
a compiler) can catch those problems.

This is discussion between static and dynamic languages and about
explicit types specification. I think there is enough discussion on
internet regarding this stuff and I worry I cannot add anything new
here.



E.g. in ycp one nil can result in cascade of nils.

I really wouldn't call YCP, of all things, a shining example of
good behaviour when it comes to this. Yet, even it had (after years
of painful debugging) static type checking that at least did some
minimal amount of plausibility checks.


What is ruby philosophy how to solve it? Tests. Do not trust code
that is not tested. Of course some tools can detect some misusage,
but only good tests can prove that code really works.

Tests are good, but they have limits. In particular, when your
number of code paths is too high, the possible permutations just
explode. That's why achieving good test coverage is so difficult.

Thats more phylosophy discussion about egg or the egg problem. Ruby
phylosophy is that if something is not tested ( manually or automatic
), then you cannot believe in code. And with good code design almost
everything can be tested.


Ruby (and the tools in its ecosystem like Rubocop) try to make you
believe that you can easily handle this by dumbing down functions
enough so they become trivial. Well, that would be good - if only
there were a practical way to go through each code path at least
once (better yet, with some permutations of your data set /
variables to test fringe cases in the less frequently taken code
paths, too).

well, trivial = single purpose. Actually what you mention already
exists for ruby - https://github.com/mbj/mutant it tests if you do not
have fake test coverage ( martin played with it in past ). Regarding
automatic tool to go thrue all path, it is still not enough as
1) that tool need to know behavior, sometimes exception is correct
2) need to verify it do what is expected, just passing function
without exception is not enough


But as seen in this example, this is often not practical. If your
code depends on the status of things beyond your immediate control,
you'd have to mock all that. In this particular case, who would have
foreseen that a seemingly unrelated scenario like having a RAID on
the previous installation might lead to such a crash?

If it happen first time like in this case I usually capture target map
( as hand crafting target map is pain ) and then write at least
regression test, that I know that covering this case.


Sure, better test coverage might have caught this. But it would
have been even simpler (very much simpler!) to have the parser
throw an error if the code is inconsistent - like not returning a
value in this case if in the other case it does.

It is question if you are on side at least have some check or having
good tests that verify working solution. Again it is part of mandatory
types discussion topic.


And to cut the reply that immediately comes to mind short: If in
some pathological case I want the code to return 'nil', I can
explicitly make it return 'nil'.

On other hand there is many cases where nil is nature return code like
in each, find, etc. So for language authors it can mean to use
specific statement for other loops or be consistent, which can cause
troubles.



IMHO there is no real excuse for the Ruby parser to behave this
dumb. They just became collateral damage of their own "anything
goes" philosophy.

I agree that faster failure during runtime will be better, but there
can be maybe code that use this code path.

Josef



CU


--
To unsubscribe, e-mail: yast-devel+unsubscribe@xxxxxxxxxxxx
To contact the owner, e-mail: yast-devel+owner@xxxxxxxxxxxx

< Previous Next >