-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Proposal: add "use" to anonymous blocks #35499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
CC @eernstg and @leafpetersen I think this could be moved to the language repo. I actually just like even a simpler concept: let blocks (anonymous, try, ...) return values. This helps assign final and non-nullable variables: final a = {
if (foo.complicatedExpression || otherThings.something) {
return 1;
} else if (some.other.conditions) {
return 2;
} else {
return 3;
}
}
String /* ! */ b = try {
// something about a connection;
} on NetworkException catch (e) {
// guaranteed block exit like throw.
throw MyDifferentException;
// or a special value
return "MAGIC_STRING_VALUE";
} |
Apologies if this is in the wrong repo, still getting the hang of the dart-lang organization layout. allowing blocks to return values would be darn cool, address half of the above proposal, and make my above example very concise and readable myFunction(){
final foo = "foo";
final bar = {
final result = "$foo bar";
return result;
}
final baz = {
final result = "$bar baz";
return result;
}
return baz;
} The other half of the proposal ( |
Although, you can already achieve this like so: myFunction(){
final foo = "foo";
final bar = (){
final result = "$foo bar";
return result;
}();
final baz = (){
final result = "$bar baz";
return result;
}();
return baz;
}
|
@srawlins Your examples are doable today with closures final a = (){
if (foo.complicatedExpression || otherThings.something) {
return 1;
} else if (some.other.conditions) {
return 2;
} else {
return 3;
}
}(); String /* ! */ b = (){
try {
// something about a connection;
} on NetworkException catch (e) {
// guaranteed block exit like throw.
throw MyDifferentException;
// or a special value
return "MAGIC_STRING_VALUE";
}
}(); The last one is also slightly ambiguous, as there are two blocks try {
// something about a connection;
} and on NetworkException catch (e) {
// guaranteed block exit like throw.
throw MyDifferentException;
// or a special value
return "MAGIC_STRING_VALUE";
} This can be confusing syntax. Also, this would make this use case more complex to understand, and more prone to syntax errors String test() {
try {
// something about a connection;
} on NetworkException catch (e) {
return "MAGIC_STRING_VALUE";
}
} String test() {
var b = try {
// something about a connection;
} on NetworkException catch (e) {
return "MAGIC_STRING_VALUE";
}
} These two are very similar and the error can be glanced over |
As I understand the proposed feature, it's not about abstraction, but about static scope restriction. It ensures that the block can only see the mentioned names from the surrounding scope. While I can see the charm of it, I'm not sure it scales to more complex blocks. Would you have to mention int foo = 42;
func() {
int foo = 37;
int tmp;
use tmp { tmp = foo; } // copy *outer* foo.
...
} That might be a little too clever. :) In either case, having to list a lot of variables might be prohibitive. So, maybe it should have something like show/hide from imports: hide bar { ... can't see bar from surrounding scope...}
show bar { ... can only see bar from surrounding scope ... } That kind of scope management is probably not worth the complexity it introduces. I'd be more inclined to add syntax that explicitly declares one or more variables with a statement block as initializer, so it's clear that this variable initialization is performed by the block, instead of the not-obviously unrelated declaration and block: int foo;
{ some block that happens to initialize foo } Imagine if you could do: int foo {
int tmp = 0;
for (int i = 0; i < 25; i++) tmp += i * i;
foo = tmp;
} where |
Yes the original idea was to restrict the ability for a block to access outside variables regardless of them being local or global. This would just promote writing blocks as pure-ish functions. I really like the idea you are proposing. I wanted to add another (orthogonal?) idea for consideration. It seems to me that in dart there is only one block modifier foo() async => /// etc What if we were to add another, perhaps Example: final global = "👹";
foo(String argument) pure => "$argument bar"; // is valid
foo(String argument) pure => "$argument, $global, bar"; // is invalid pure would force a function to only consume its inputs. I am unsure if this is more of a linter warning type of feature or a language level feature. |
Drive-by comment: We have had several requests for constant function literals, all the way back to 2012, and they would be required to denote the same function also in the case where more than one entity is associated with a name from an enclosing scope. This would imply that local variables and instance variables from enclosing scopes cannot be accessed, but it would allow access to static and top-level variables, and it wouldn't prevent side-effects. @lukepighetti, would that address the request of this issue? It seems rather similar to your |
Hello,
I have been using anonymous blocks to break up long procedural code that will not be reused anywhere. I ran into an interesting idea for a language feature that I think would be a great addition to Dart. I can imagine there being a lot of apathy towards this proposal due to procedural programming being seen as "old", but since all applications use procedural to some extent I think its worth considering.
Here is a function using anonymous blocks. Its not a shining example, but it gets us started! The nice thing about anonymous blocks is that they encapsulate the scope within steps in procedural code while preserving the order to the reader. Do this, then this, then this. All the code is there and easy to reason about. The problem is that these anonymous blocks perform shadowing and its not clear what variables from the parent scope are being used.
Many people would rewrite this as below. Problem is, its not sequential, harder to understand (although so common many would argue this is not a consideration), and makes non-repetitive code very repetitive in a way that normally supports reuse but in this case reuse is not valued.
Proposal: Allow strict scope for anonymous blocks.
Introduce a
use
keyword that restricts the scope of an anonymous block to the variables provided touse
.An example with multiple arguments might be:
The text was updated successfully, but these errors were encountered: