This was originally meant to be posted at rakudo/rakudo#5390. Since I have put effort into it and I do think there is thought in it, I decided to preserve it despite the blockade thrown into the way.
Anyways. There's the blog post and the discussion. The fact that Slang::Otherwise has 5 stars on Github is some indication that the repo is appreciated by some people at least.
I'm not arguing against the existence of a slang. I'm arguing against throwing it into the core language, let alone by a mere PR. I don't think the discussion even looks so clear and one-sided from a neutral point of view, and I think I have seen this article before.
I would like to respond to the article itself in this comment... that will be enough for now I think.
I needed to build an object for every value in the
@values
array, or a single special object if@values
was empty:
I think this is basically where we parted. Why do you want to make zero values have an interface like it was one value? Well, let's see.
I checked the referenced article and I think it's a great illustration of how memes of the Dawkinsian sense work. To quote the problem as the author phrased it:
The only thing left to do is to cover the edge-case where the user provides no test values at all (i.e. when there are no
@values
to iterate through). That can happen either when an explicit empty list of default values is passed to assert, or when the block passed in doesn’t explicitly declare a parameter at all (and therefore defaults to the implicit topic parameter: $_). In either case, we need to call the block exactly once, without any argument.
This is an interface question. If your interface is "here, give me a couple of values to perform tests on", it makes perfect sense to do nothing when you receive no values. The author didn't like this interface and instead of adding a special case for no values at the interface level ("if the user provided no values, it's considered to be this one special value"), they propagated the "raw" interface to the implementation. The funny thing is, if you assign something like Nil
or Any
to a @variable
in Raku, you would actually get behavior that is fitting for this interface...
So this is the reason I don't see code like this as much as Perl folks do. We have completely different first thoughts when we come across a problem, and probably partially because of how we learned the language or programming in general. If you want to treat no data as one unit of data, do just that - this seems to be the much more common approach in other languages. Also, that way, you can decide to carry the one unit you decided on as much as you want, as meaningful data to the backend. This actually seems like better layering: you translated the interface at a reasonably high abstraction level and the low levels don't have to do any business logic anymore.
At almost the same time, in other (non-blog) code I was writing, I needed exactly the same construction...to do something with every element of an array, or something different if the array had no elements:
for @errors -> $error {
note $error if DEBUG;
LAST die X::CompilationFailed.new( :@errors );
}
if !@errors {
note 'Compilation complete' if DEBUG;
return $compilation;
}
I think here it really makes a difference that it's not any array we are dealing with but an array of errors, and "there have been some errors" and "there have been no errors" are really two fundamentally different cases, regardless if you retrieve this information as "is this array empty" or by checking a status code, having a boolean flag, etc. Here, the if-check actually has a meaning - frankly, in this case, it doesn't even seem nice to run a loop through the errors and rely on the emptiness of them. In a situation like this, the whole control flow of "there are errors" and "there are no errors" can be expected to be different and it seems accidental that the author wanted to do nothing besides the loop for the error case. (Actually, the error did already do something besides the loop, using the phaser.)
So in general, this code would really look like:
if @errors { # or whatever check for an error
# do some stuff maybe
for @errors -> $error {
# do something for each individual $error
}
# do something afterwards, maybe halt the program, dump a file, etc.
}
# maybe an else clause if the error case isn't escalated here
In this structure, it's visible that the "happy path" doesn't belong to the loop itself but the whole error handling, so I wouldn't say this use of for-otherwise would be common or even idiomatic.
but that just underscores the absurdity of needing to test the state of the iterated array twice within the first two lines.
I don't know if it was ever absurd (talking about strong judgemental language) but it's surely not absurd in my snippet where going through the actual errors is just one tiny part of the error handling and nobody - okay, not most people - would get the idea that the for
is there as an if there-was-an-error
check.
So, from what I see, these were the two examples provided, all I can respond to.