Its possible that's a bug and not an intentional design decision. I certainly hope it is, because I agree with you that it doesn't make sense to hide it behind a pragma but have this workaround.
I mean, it makes some degree of logical sense (toString -> concat) but there is no reason that would ever be the intended behavior.
As for that expression, meh. You can write intentionally obtuse code in any language. The problem with JS is the behavior that is different from what you'd expect.
No, in perl eval explicitly has access to the local scope. This is used for capturing otherwise fatal errors in perl (it can be used similarly to try/catch).
Wouldn't the handlers for exception handling by dynamically scoped, not lexically?
If we have a try block, and call a function, and if that function throws, we want the try block to be able to catch that. The function is not understood as having magic access to an environment; it's a pervasive dynamic environment that is visible to the current execution context at all times, in which exit points for non-local transfers are established.
That's almost the entire point since an error situation that is entirely confined to a lexical scope can be dealt with using some local control flow (some form of goto, or structured derivative thereof).
So with perl 5 there isn't a real exception handler like you'd expect from other languages (I'm unsure of perl 6). It works like the following (program output available at [1]):
use v5.24.0;
my $x = 1;
my $y = "bar";
sub foo { # this sub fails fatally
die "what is going on here";
}
say "x is $x, y is $y"; # 1 and bar
eval { # similar to try
my $y = "baz"; # we have a new lexical scope in here too.
$x = 2; # but this will change the outside scope since it's also available to us
say "x is $x, y is $y"; # 2 and baz
foo();
$x = 3; # this never happens
};
if ($@) { # check for an error, similar to catch
say "CAUGHT ERROR: ", $@; # just parrot the error out for now.
}
say "x is $x, y is $y"; # 2 and bar
Inside the eval the lexical scope outside is still available and a new one is also available. The error that happens gets stuffed into a special variable and you can choose to handle it or not later. This works the same way if you give eval a string to run also.
My biggest question about this is did the guy not understand why the flag was called `MONKEY-SEE-NO-EVAL`? Because that name was my favourite part of the article...
I think that the author does get the pun; they made another of a similar calibre in the title of the post!
Their main objection to the pragma would seem to be the MONKEY-SEE-NO-EVAL name; if you don't understand the reference, say you're a non-native speaker, or just have no idea what it's referring to, all you'll see is "NO-EVAL", and then get confused why the code suddenly allows EVAL everywhere. Levity and fun is perfectly acceptable, but is it just as acceptable when the language is less obvious for it's extended developer community?
His point is merely that either this is a seriously bad idea that you should never do, in which case you should not attempt to communicate it through a silly pun, or it is acceptable, in which case it shouldn't be hidden behind a compiler pragma.
Yes it's cool but maybe not everybody gets the drift. That and the fact that Perl6 error messages are really meaningful as in not a wordplay on a reference to sanzaru.
It's worth noting that eval in perl5 can be used with a codeblock to give basic exception handling, in perl6 this functionality has been moved to try. So while it's quite common to use eval in perl5, I'd expect much less usage in perl6. The name change is probably a good reminder of this.
Is it really going to be safe to use? I don't know Perl that well, but it feels like there's enough language features to make a safe eval harder than writing your own parser for a DSL. That's certainly the case for Python: https://nedbatchelder.com/blog/201206/eval_really_is_dangero...
Python's eval is crippled, it can't take a full environment.
Suppose for a moment that the scope of eval was truly an environment:
And you don't supply the resulting environment with anything but the functions you want.
Not even the dot operator, let alone magic builtins.
Python's eval suddenly becomes much safer. Unfortunately such an eval is harder to implement in Python, because every object carries it's magic methods with it, rather than looking them up elsewhere.
Sure! Most of the time, it just makes it easier to parse and interpret input in a safe manner.
* Racket [0], sometimes used when you don't want to use Racket's way of designing DSLs, or if you want to interface to databases simpler.
* Scheme [1], used when designing DSLs, interacting with databases. You often see it go hand-in-hand with X-Expressions.
* Lua [2] can, but it is rarely used.
Note, the link for Lua actually lists a whole host of languages where this can be technically done, but not all are entirely safe.
I think it's uncommonality is not because of it's inconvenience or rarity, but rather the mantra of 'eval is evil' in the programming community, even when it doesn't apply.
E and Monte have safe eval() as a consequence of being object-based capability-safe languages; there's no way to cause any effect outside eval() worse than an infinite loop.
To the second part of your question: as you have undoubtedly noticed, you've never heard of E nor Monte.
Python wasn't designed from the start with this kind of security concern in mind. It could have been, like http://erights.org/. In such languages it's reasonable to say "you can write a user-level drop-in replacement for eval(), and therefore we can make the built-in eval accessible to all code without any extra security-design concerns" (though of course you still need care in implementation).
A block isn't a sandbox, and the base language itself has everything one needs to shoot gaping holes in feet. I'm not sure how handing off an empty (or whatever) environment to the eval'ed code can be "safe".
I agree with the author that this is probably overkill, in terms of warning about eval, but I'm also not understanding how merely having a block with a block scoped environment can make eval safe.
Maybe I don't understand the meaning of "blocks" in Perl 6 (if they work this way, I definitely don't understand them). I've never worked in Perl 6, except a couple of tutorials, so that's entirely possible. I mean, I know Perl 6 has the ability to fundamentally change the language within the language itself.
The only thing blocks have to do with this, is that Perl6 has to internally track state so that closed over values go out of scope when their parent block ends. End of story.
Maybe I can try explaining again.
Eval is unsafe as it reads input values in terms of the current state of a program.
It's environment is implicitly given, and includes the entirety of the Perl6 language, as well as anything user-created.
But, what if the programmer was allowed to supply that context?
Rather than a blacklist against certain bad things, this is a whitelist where you supply every single thing that eval is allowed to use.
Other languages already have this.
Scheme example that works:
(eval '(+ 1 2) (let (null-environment) '(+ . +)))
Scheme eval that fails:
(eval '(+ 1 2) (null-environment))
Perl6's flexibility is less unsafe when you don't provide anything flexible.
So in order to use a function that exposes the software to serious undue security risk unless used correctly, the engineer is pushed to do research? That really doesn't seem like a bad thing...