-
Notifications
You must be signed in to change notification settings - Fork 205
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
Destructuring #207
Comments
For more inspiration, I'll add some Swift examples. Tuples & tuple desctructuringlet tuple = (1, "A")
let (x, y) = tuple Tuple dot notationlet triple = (1, 2, 3)
let (a, b) = (triple.0, triple.2) // a = 1, b = 3 Binding with pattern matchingswitch tuple {
case let (x, y) where x > 0 && y == "A":
print(x, y)
case let z:
print(z)
} Binding with for loopslet dictionary = [1: "one", 2: "two", 3: "three"]
for (key, value) in dictionary {
print(key, value)
} Wildcardsfor (_, value) in dictionary {
print(value)
}
switch triple {
case let (a, _, _):
print(a)
} |
BTW it will allow a sweet feature like swapping data without necessity of temporal variable, e.g.: Currently: int a = 1;
int b = 2;
int tmp = a;
a = b;
b = tmp; with destructuring: int a = 1;
int b = 2;
[a, b] = [b, a];
a; // 2
b; // 1 |
Yup, that's covered in the proposal. |
The proposal only details destructuring in the context of assignment, such as in variable assignments/declarations, or in loops. But I'm seeing quite a potential here for using destructuring in the context of function/constructor/accessor arguments, as is the case in Python. ExamplesThese examples have all been written in Python. Iterable unpackingdef my_function(x, y):
print(x)
print(y)
my_tuple = (1, 2)
my_function(*my_tuple) This prints the following;
Mapping unpackingdef my_function(x, y):
print(x)
print(y)
my_dictionary = {'x':1, 'y':2}
my_function(**my_dictionary) This prints the following;
It also works in reverse; my_dictionary = {'y':2, 'x':1}
my_function (**my_dictionary) This will print the following
NOTE See the Python specifications for a more comprehensive look at the "unpacking" functionality IssueThe problem that this concept poses, is the proposal's lack of an operator like the |
.. several posts irrelevant to the issue of destructuring - deleted by the author |
@tatumizer I've already published a test on the repo which eliminates the possibility of a significant performance differential between positional, named and mixed arguments in the verbose method. I will also be doing other performance tests in the repository, but maybe it would be interesting if you open an issue on there with your test's source code? That way I can also provide some feedback and possibly replicate the test my self to compare the results. EDIT
|
I was aware of that, my report's hypothesis states that I did not expect any significant difference between named and positional arguments in verbose code. The reason I tested it was just to make sure we weren't going off a wild guess. |
That sounds like a good idea, anyways, I'm going to make a generic API for running tests, although I need to see if the overhead is not to much (maybe I could over-engineer this a bit with a web panel with fancy graphs and the ability to monitor tests remotely :)......) |
Lists are not tuples, so I would't use For a tuple-based syntax like |
I won't put my money on any specific tuple type syntax yet, too many options are open. I intended The point of tuples, maybe even named tuples like You can spread a list in a list, or a map in a map. You can't just spread a map or list in a parameter list because it's a different structure with different requirements (like a per-element type), but a tuple can be an abstraction with the same structure as a parameter list, so it would make sense to spread a tuple in another tuple, or in a parameter list. (Maybe |
Tuples with |
You write a one-tuple as |
In Swift, you're using the empty tuple basically everywhere without even noticing: public typealias Void = () |
If we had tuples, maybe we should just make |
It's unlikely that the zero-tuple type |
No. Ob-digression: Tuples are product types. If you see types as sets of values (which is a slightly naive mode, but useful) then the tuple type In general, then From that it follows that the zero tuple, Up to isomorphism, all one-element sets are the same, and a one element set is is the neutral element wrt. set products (let The empty set is the neutral element wrt. set union, but an eliminator wrt. set product. It's similar to how 0 and 1 work with multiplication in the non-negative integers. In this sense, the unit type and the empty type are very different, and bottom is the empty type, while the zero-tuple is the unit type. |
@tatumizer; aren't empty parameter lists such as in |
It is not true from mathematical perspective 0^0 commonly evaluated to 1 or less often to undefined, see: https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero |
It'd be interesting to have it for classes too. Consider the following class: class Foo {
String foo;
int bar;
} we'd be able to do:
which would be equivalent of: final obj = Foo();
final foo = obj.foo;
final bar = obj.bar; |
Javascript is a good example of how we can have both.
const [first, second] = [0, 1];
const {length} = [0, 1]; |
Javascript is sometimes but not always a good example that we can follow in Dart. One key difference is that JavaScript does not distinguish maps (data structures) from objects (instances) while Dart does. That means that, unlike Javascript, we can't naturally use var map = {"length": "not 1!"};
var {length} = map;
print(length); // 1, or "not 1!"? |
What about:
vs
? This follows the logic of And it would be the same for any |
Something worthy of mention is that it is possible to put anything as keys of a Map. IMO the tree cases are not List/Map/Objects. But instead:
I would expect the following to work: var [foo, bar] = {0: 'foo', 1: 'bar'};
print('$foo $bar'); // foo bar Which means the behavior of destructuring is not based on the type of the object, but its This has a few implications. First, it means that any objects that override class Foo {
int operator [](int index) {
return index;
}
}
var foo = Foo();
var [first, second] = foo;
print('$first $second'); // 1 2 Secondly, it means that Their meaning could be different:
Since Dart is typed, the behavior of Such that we have:
var [first, second] = {0: 'foo', 1: 'bar'};
print('$first $second'); // foo bar
var [foo, bar] = {"foo": 42, "bar": 24};
print('$foo $bar'); // 42 24
var {length} = {};
print(length); // 0 The case of Tupples is unchanged because they can't be accessed with |
I don't see the need for this special syntax. The destructuring syntax should mirror the literal syntax, with non literals being bound variables. For instance, going back to Scala, there is no List literal. Instead there is a List val List(a, b) = someList Similarly with Map (where there is also no literal syntax: val Map("a" -> 0, "b" -> 1) = someMap It's nice in the fact that it is obvious what you are trying to destructure. In other languages with nice facilities for destructuring and pattern matching, data structures for which there are literals(which is usually about everything) things map very cleanly. For example, Elixir - a really popular language at the moment: some_list = [1, 2, 3]
[a, b, c] = some_list
some_map = %{"a" => 0, "b" => 1}
%{"a" => a, "b" => b} = some_map
some_keyword_list = [a: 0, b: 1] # This is special Elixir data structure, the keys are atoms
[a: c, b: d] = some_keyword_list
a_tuple = {:ok, [1, 2, 3]} # :ok is an atom
# The next two are both ok
{:ok, list_from_tuple} = a_tuple
{:ok, [a_from_list, b_from_list, c_from_list]} = a_tuple So if the desire is to have similar facilities here (which I'm not assuming), it could and maybe should like like the following in Dart: final someList = [1, 2, 3];
final someMap = {"a": 0, "b": 1};
final someClassInstance = SomeClass(param1: "a", param2: 3);
final [one, two, three] = someList;
final [head, ...tail] = someList;
final {"a": zero, "b": mapOne} = someMap; // How to represent non string keys? In JS, an object is an associative array of string -> JSValue
final SomeClass(param1: instanceA, param2: instanceThree) = someClassInstance; Now there are still problems here. Elixir is a dynamic language, with a philosophy of "let it crash" so these sorts of destructurings that may in fact raise can do so and the system will chug along. In Scala, this type of naked destructuring is discouraged, except for class instances, since the object does in fact exist and there are certain guarantees around the values exposed through That's kind of a long winded way of saying that most of these naked destructuring patterns are not well suited for a static, strongly typed language. What is useful on the other hand is to take the thoughts and conversation around destructuring and apply it a sane system of pattern matching. That's my opinion, but I think it would be a footgun to allow native destructuring of the type Javascript and Elixir(dynamic languages) give in a language like Dart. |
I don't think it's too bad @tatumizer, but are you sure that this does not conflict with the current assignment syntax? Or is this mitigated by the use of curly brackets ( I'm sure we're onto something here, but I think we need to make sure that we've thought of the edge cases so that the syntax we come up with is adequately robust. |
Okay, which function is a duplicate of the other: this, or #68? Either way it seems if you fix one, you fix the other. |
Very useful syntax! |
Neither are strictly duplicates. There are some languages (Lua, Go) that allow multiple returns without actually reifying them into a single destructurable object. |
What's the status on this ? Builtin tuples and destructuring has been a thing for like half a decade in C# and other languages. |
We haven't had time to work on it recently. Destructuring is on my plate, and static metaprogramming has been keeping me busy. I am hoping to resume working on it fairly soon. |
Lovely. Thanks for the quick update! |
Excited for this. Thanks for the hard work! |
This comment was marked as off-topic.
This comment was marked as off-topic.
Is this no longer under discussion? What state is this issue in? |
Destructuring is now part of the more general "patterns" design proposal. As you can see, it's actively being discussed. |
I guess it would be good to edit the original post to add this info |
Hello.. Despite the "patterns" label as mentioned in #207 (comment), it still looks as if the discussion is not moving forward.. given there's no update on the decision. Is it safe to consider it as being indefinitely shelved? |
I think this issue can be closed as #546 has taken over. |
Hi I don't think this issue should be closed :) otherwise it will appear in #546 as if the item has been completed [1], unlike the other items like [2]. Maybe a better strategy is to leave the issue open, but add a notice on the first post that this is being tracked in #546 and no more updates are expected on this post itself. |
Ack, let's do it that way. |
I'll go through everything labeled "patterns" and clean it up once it ships. :) |
How's it going? No disassembly, it's a pain :) |
It's going awesomely, check: https://medium.com/dartlang/dart-3-alpha-f1458fb9d232 |
Closing this because records and patterns are now enabled by default on the main branch of the Dart SDK! 🎉 |
Destructuring is now parts of the patterns feature, and tracked by the specification of that (#546).
No further updates are expected to this issue, it's kept open only as a representation of the status of that particular part of pattern matching.
Dart could have some way to easily "destructure" composite values.
Example proposal from the DEP process: https://github.com/DirectMyFile/dep-destructuring (by @kaendfinger).
The text was updated successfully, but these errors were encountered: