Comments (14)
Well, it can:
You missed the point. The actual iterator logic is in map
lexical scope, actually. :)
from problem-solving.
Just an example:
sub transform($v) {
next if $v.contains("2");
"<$v>"
}
say (^20).map(&transform);
Even the .map({...})
form is a good demonstration because the code block just cannot be in the same lexical scope where the iteration logic is located.
from problem-solving.
A different way to phase this issue would be "next, last, and redo should have lexical scope rather than dynamic scope"
I don't think this reflects the Block
vs Sub
distinction. It's super useful and also fairly reasonable that a Block
is transparent to all control structures. It could even look up all variables dynamically - I can imagine why that might be a bad idea but it could also make some sense. However, to have a subroutine that can be safely used as an independent unit of execution, is a different story.
it's very clear that gather is supposed to have dynamic scope, and next/last/redo "feel" similar enough to gather that I'm inclined to think that keeping their behavior consistent is the better design.
It seems to me that both statements can be challenged. I do think that take
could also be taken as a cunning implicit callback and be subject to evalutation whether it's really worth it to let it slip through subroutines. However, let me point out that take
does indeed have more of a callback interface that next
, last
and the likes don't have, and maybe for the better:
use v6.*; # To enforce next, last with return values
gather for (1..10) { .take } # This is going to work
(1..10).map: { .next } # This won't - has to use `next $_`
(1..10).map: { .last } # This also won't - has to use `last $_`
Now, of course those control statements could be adopted to also have the OO-looking interface - which is also a modification that might interfere with existing code, and then we can still ask if it's really expressive or just confusing.
from problem-solving.
My proposal would be to keep control exceptions like the ones next
and last
create, inside Sub
s, hence throwing a similar exception to a legitimately missing loop to iterate.
If somebody prefers the former (perhaps unspecified?) behavior:
- they can specify a CONTROL phaser to pass it through anyway
- I don't know how you feel about pragmas but there could be one to set the behavior for one
Sub
or the wholeCompUnit
, for example
The topic of performance also came up from @lizmat . My stance on that is (besides the general sentiment of "it's better to be right slowly than wrong quickly"): the implementation doesn't need to be fast immediately. Loads of control structure optimizations will be available with RakuAST - in fact, most of the time, we could say it at compile time if an invalid next
is used in a subroutine, by traversing from the usage of next
towards the root Sub
. At the very least, we can omit special handling when it's clear that there are no such control statements, or they are clearly scoped in a loop inside the Sub
.
from problem-solving.
The synopses actually do mention the dynamic nature of a bare
next
(as opposed to a labellednext
, for example) - however, this doesn't appear anywhere in the corresponding file of the specification.
See https://github.com/Raku/roast/blob/master/S04-statements/last.t#L31-L39 for last
.
from problem-solving.
The synopses actually do mention the dynamic nature of a bare
next
(as opposed to a labellednext
, for example) - however, this doesn't appear anywhere in the corresponding file of the specification.See https://github.com/Raku/roast/blob/master/S04-statements/last.t#L31-L39 for
last
.
I think this is the right place for design decisions anyway - so then the amendment woud be: introduce this in a new version, and modify the corresponding test.
from problem-solving.
Hmm, my (tentative) thought is that the current behavior is reflects the correct design. A different way to phase this issue would be "next
, last
, and redo
should have lexical scope rather than dynamic scope". But, phrased like that, I'm slightly inclined to disagree – it's very clear that gather
is supposed to have dynamic scope, and next
/last
/redo
"feel" similar enough to gather
that I'm inclined to think that keeping their behavior consistent is the better design.
On the other hand, lexical scope is more familiar to most programmers and I don't have strong feelings on the matter. So I'm certainly open to persuasion.
from problem-solving.
Even the
.map({...})
form is a good demonstration because the code block just cannot be in the same lexical scope where the iteration logic is located.
Well, it can:
say (^20).map({
next if .contains("2");
"<$_>"
});
But, more generally, I agree that there are times when a dynamic scope to next
is useful/clearer.
from problem-solving.
Even the .map({...}) form is a good demonstration because the code block just cannot be in the same lexical scope where the iteration logic is located.
The .map({...})
form uses a Block
, not a Sub
. I'm not arguing against this behavior for a Block
but a Sub
. And consequently, that example looks like a good illustration of what I find confusing without any benefits.
from problem-solving.
I'm not arguing against this behavior for a Block but a Sub.
IMO having this behavior differ between Blocks and Subs would be highly confusing.
from problem-solving.
The
.map({...})
form uses aBlock
, not aSub
. I'm not arguing against this behavior for aBlock
but aSub
. And consequently, that example looks like a good illustration of what I find confusing without any benefits.
Are you sure about no benefits? I consider the transform
sub from my example to be very beneficial as means of code clarification and organization. .map(&transform)
(or .map: &transform
) seems to be way more self-explanatory than using a block with all the same logic transform
provides. Basically, the routine should've be named transform-and-filter
for the full clarity of it.
IMO having this behavior differ between Blocks and Subs would be highly confusing.
Not exactly. Think of return
which is routine
-scoped, so to say. The other point is that its semantics greatly differs from that of next
and its "kins".
from problem-solving.
Just to throw in another code example that could potentially confuse me:
for @lists -> $x {
$x.map({ process($_); next if !$_ }
}
from problem-solving.
IMO having this behavior differ between Blocks and Subs would be highly confusing.
Well, what can I say, I think this is the whole point Block
s exist in the first place - to represent a piece of code with a scope that can be abstracted away while still providing inlining semantics. I can't see why this would be confusing - rather than Sub
sometimes mimicking inlined behavior, by implicitly passing control flow back to the caller...
from problem-solving.
The other point is that its semantics greatly differs from that of next and its "kins".
Well, does it? Are they not all pragmatisms over structural code, sort of jumps that are at least guaranteed to be tied to certain control structures? I would say return
and next
are much more alike than take
and next
- I wonder if take
is considered a control statement to begin with, it's not obvious at least. By semantics, it's much more like a callback.
Also, food for thought: linked part of synopsis also says For instance, next with a label will prefer to exit a loop lexotically
- and this is present in the current workings as well. next BAR
isn't going to fall through anything but a bare next
will - does this inconsistency seem as good as it did back when this language was going to be the new Perl?
Also, if one does want the fallback behavior for a subroutine, it could still be made explicit, right? I have mentioned the idea of a pragma but at the end of the day, I wouldn't oppose something like next *
either. The asterisk even plays nice with the symbolics of dynamic behavior.
.map(&transform)
(or.map: &transform
) seems to be way more self-explanatory than using a block with all the same logic transform provides
I'm afraid this is a "let's agree to disagree" situation - that seems to me like a misuse of a subroutine. To me, it breaks the expectations of a subroutine - the expectation that a successfully executed subroutine won't interfere with the code of the caller - after all, that's part of the reason why I abstracted it away with a subroutine and not a Block
, right?
It can actually lead to weird thoughts: what return value does that subroutine even have? After all, next
is not a callback, and indeed it terminates the control flow of the subroutine in the first place. Indeed, it behaves like an exception, without looking like one.
Just to throw in another code example that could potentially confuse me:
for @lists -> $x { $x.map({ process($_); next if !$_ } }
@patrickbkr Could you please elaborate? Because here the for
loop seems superfluous. So far, I haven't seen anybody questioning that map
˙implies a loop, therefore all possible uses would hook up there, if anywhere.
from problem-solving.
Related Issues (20)
- Metamodel concurrency problems HOT 17
- Named arguments don't respect canonical `key => value` convention (specific example of `mm-dd-yyyy` routine) HOT 15
- Add `.bufs`/`.blobs` methods to `IO::Path` / `IO::Handle` HOT 6
- `when` doesn't support smartmatching against a pointy block HOT 8
- Code highlighting / inspection / IDE tooling HOT 6
- Using multiple named arguments gives different result than just supplying value alone; specific example of `splice`. HOT 22
- Will we ever need more than 64K unique strings at compile time? HOT 4
- Add "short-index" version of often occurring ops HOT 1
- Behavior of type-constrained parameters is surprising given other behavior HOT 65
- Add `nomark` for striping accents, `samemark` is counterintuitive and slow for that purpose. HOT 3
- Root(s) - missing prefix operators HOT 1
- Enabling `no strict` for `raku` one-liners (and perhaps REPL) HOT 8
- Should `.flatmap` be really DEPRECATED or not? HOT 6
- Feature Request - method ```.hammer``` HOT 19
- Hash slices should have an option to return a hash HOT 28
- Feature Request: recognize "doubled" Unicode characters in Raku ternary operator (question mark and exclamation point). HOT 6
- DivideByZero exception has conflicting attributes HOT 5
- X::Numeric::CannotConvert vs. X::Numeric::Real HOT 1
- Routines shift and pop on lists should allow an option to pop or shift multiple elements in one op HOT 6
- `uniprop` and friends are buggy, inconsistent, and potentially replaceable HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from problem-solving.