Skip to content
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

White-space dependent destructuring typing and renaming. Breaks backwards compatability. #33

Closed
sirisian opened this issue Feb 19, 2018 · 9 comments

Comments

@sirisian
Copy link
Owner

Take the example below that assigns a new variable name in the destructuring assignment:

let { a: b } = { a: 2 };

Is b a type or a new variable name? This isn't clearly defined and there's no way to infer this from the identifier.

Also consider a typed example with renaming:

let { a:b: b } = { a: 2 };

Ideally the code would be white-space dependent. ": b" means renamed and ":b" would be a type. This is unconventional, but it's been my design and I had forgotten about it.

That said creating white-space dependence in this syntax is a breaking change to the spec which makes it nearly impossible to propose? That is there is probably already large amounts of code that uses renaming without a space.

It is the most elegant solution though to introduce this breaking change I believe, but I'm not sure it would be possible. Any ideas?

@sirisian
Copy link
Owner Author

sirisian commented Feb 21, 2018

I just realized it makes far more sense to put the type with the renamed variable.

let { a: b:b } = { a: 2 };

One reads it as map a in the right hand side to b with the assigned type b and then shadow the type b. (Variable shadowing).

Also in case it wasn't clear if the right hand side is typed one can just use typed assignment from the spec. That covers a lot of cases where the type is inferred from the right hand side function.

let { a: b } := { a:uint8: 10 }; // b is type uint8.

I had someone ask about this because he mentioned that most of his use cases are from function returning multiple, already typed variables.

It's possible we could just not include destructuring typing at all. The main use case is where you want the type to be type casted in a compact way from the type in the right hand side object.

let { a:uint32 } = { a:uint8: 10 };

Why did the language designers choose to use : for the token to separate the renamed variable! I think this is the only instance where it's used like this. Maybe we can create our own better syntax.

let { a=>b:uint32 } = { a:uint8: 10 };

The => in this case is read as "to" or "as". "Assign the value a in the right hand side to b with type uint32.

The problem is => is already a token. Then again so was : and they gave it more meaning. That said this creates two ways to do the same thing. It's a good thing I'm in no rush trying to design around these problems.

@Avol-V
Copy link

Avol-V commented Feb 21, 2018

Why you want to break syntax?

Just do it like in TypeScript:

const o: {a: uint8} = { a: 1 };
const { a: b }: {a: uint32} = o;
// b is uint32

@sirisian
Copy link
Owner Author

I don't want to break any syntax. Maybe I should have been more clear that my original discussion was more of a "this can't work and needs changed". Like a number of things in the spec I wrote them quickly to create discussion. If I write something, then someone can say it's wrong and it starts the iteration.

As for the TypeScript syntax, I found that slightly redundant and hard to read. (The TypeScript documentation even make this point that it's confusing). It's like a single level object schema. It's possible it could grow on me, but I don't think it's an ideal syntax.

@Avol-V
Copy link

Avol-V commented Feb 21, 2018

I think it’s not a common situation that we need to change type of variable with destructuring so it can be a bit redundant.

@sirisian
Copy link
Owner Author

sirisian commented Feb 22, 2018

I think you're probably right. I've updated the spec to include your suggestions. I do have one last issue. Do you know why TypeScript doesn't type the renamed variable, but rather the property? Seems strange to me.

let { a: b = 1 }: { a:uint8 } = { a: 2 };

vs

let { a: b = 1 }: { b:uint8 } = { a: 2 };

I've been staring at:

let { a: b = 0, b: a = 0 }:{ a:uint8, b:uint16 } = { a: 1, b: 2 };

It doesn't sit well with me that I can't immediately create an intuitive understanding from the example.

@Avol-V
Copy link

Avol-V commented Feb 22, 2018

Maybe it’s better to use original structure than declared variables, so we describe where in it we want to change type. But it might be less redundant with deep destructuring.

Both situations are much clear with deep destructuring example, like this:

const o: { a: { a2: uint8 } } = { a: { a2: 1 } };
const { a: { a2: b } }: { a: { a2: uint32 } } = o;

Is this clear enough if we wrote { a: { a2: b } }: { b: uint32 } here?

@sirisian
Copy link
Owner Author

Okay, I think we're on the same page. Last example (probably) using arrays in objects:

const { a:[, b] } = { a: [1, 2] };

And we want to type b. Do we use:

const { a:[, b] }:{ a:[, uint32] } = { a: [1, 2] };

or allow:

const { a:[, b:uint32] } = { a: [1, 2] };

Consider:

const { a: { a2: b, a3: [, c] } }: { a: { a2: uint32, a3: [,uint8] } } = { a: { a2: 1, a3: [2, 3] } }; // b is 1, c is 3

vs:

const { a: { a2: b, a3: [, c:uint8] } }: { a: { a2: uint32 } } = { a: { a2: 1, a3: [2, 3] } }; // b is 1, c is 3

@sirisian
Copy link
Owner Author

sirisian commented Mar 16, 2018

I just found this:
facebook/flow#235 (comment)

That whole thread goes through a lot of ideas. I have to say I did not even think of using parenthesis. His proposal B is nice.

Your example becomes:

const o: { a: { (a2:uint8) } } = { a: { a2: 1 } }; // deep casting
const { a: { (a2:uint32): b } } = o;

My complex example becomes:

const { a: { (a2:uint32): b, a3: [, c:uint8] } } = { a: { a2: 1, a3: [2, 3] } }; // b is 1, c is 3

edit: TODO: array typing when casting:

const o: { (a:uint8[]) } = { a: [0, 1, 2] };

Does this work for arrays of objects? Investigate the downsides of deep casting syntax in general.

@sirisian
Copy link
Owner Author

sirisian commented Mar 19, 2018

I've added in the parenthesis grammar into the spec. I'm going to close this.

I'm not sure if nested casting is a useful feature to discuss. It seems useful in cases where a function is returned and one wants to compactly modify type the object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants