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

[Experiment] type resolved arr[idx] #11749

Closed
wants to merge 2 commits into from
Closed

[Experiment] type resolved arr[idx] #11749

wants to merge 2 commits into from

Conversation

dsyme
Copy link
Contributor

@dsyme dsyme commented Jun 29, 2021

This is an experiment to allow type-directed arr[1] instead of arr.[1] for associative lookup and slicing syntax

Note that known type information would always be required, e.g.

let f (x: int[]) = x[0], x[1]

because

let f x = x[0]

exists today in F# and infers x to be a function x: int list -> 'a. In this case we would give a deprecation warning on x[0] to say "please add a space indicating function application or a type annotation indicating array loop" i.e. x [0] for the former

@dsyme dsyme changed the title [Experiment] type resolved lookup syntax prototype [Experiment] type resolved arr[idx] Jun 29, 2021
@auduchinok
Copy link
Member

auduchinok commented Jun 30, 2021

In this case we would give a deprecation warning on x[0] to say "please add a space indicating function application or a type annotation indicating array loop" i.e. x [0] for the former

In some cases the fix would require adding parens or a dot, like in f g[i] where f g [i], f (g [i]), and f g.[i] would mean different things.

@auduchinok
Copy link
Member

Do I get it right that we'll now allow two different syntaxes with one of them available only on some expressions and only after type checking a file? If yes, I think it adds even more confusion, especially when inferred types change while editing a file.

Could we always parse x[i] as an indexer/slice access? It's a more breaking change, but it's much more consistent and seems to add less confusion than type-directed-allowed syntax.

@dsyme
Copy link
Contributor Author

dsyme commented Jun 30, 2021

In some cases the fix would require adding parens or a dot, like in f g[i] ...

Is this is the case? There is no currently valid code f g[i]:

> f g[i];;

  f g[i];;
  --^^^^

stdin(1,3): error FS0597: Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized

There is currently valid code f g.[i] but this would become f g[i] (let's call g[i] "high precedence indexing", which would be allowed in curried argument position).

only after type checking a file?

No - the arr.[i] syntax has always been type-directed, so there is no substantial difference in processing, e.g.

> let f x = x.[1];;

  let f x = x.[1];;
  ----------^^^^^

stdin(1,11): error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints

The history here is

  1. We inherited the syntax from OCaml, which uses it in a non-type-directed way to always mean string access (so arr is inferred to have type string)
  2. We then modified it to be type-directed in F# 1.x (to work with arbitrary indexable types), and dropped the default assumption that it is string access

we'll now allow two different syntaxes

So far this is an experiment to check feasability. However, if the experiment doesn't indicate any breaking changes, and we proceed to an RFC, than yes, we'd have two ways to do things and have to work out what to do.

Of course we'd only do really this change if we intend arr[i] to be the long-term destination, so we'd need to decide on policy for arr.[i] syntax as part of an RFC for this change. We could deprecate it with a warning, or add an informational + codefix. I assume we'd do the latter.

Could we always parse x[i] as an indexer/slice access? It's a more breaking change

This is not a breaking change (at least, that's what I'm assessing - I don't believe it is so far)

Regarding parsing - yes, I expect so. Right now I'm currently not too fussed what the syntax trees are. The implementation technique in the PR at time of writing is

  1. always parse expr.., ..expr and expr..expr as SynExpr and then disambiguate later.
  2. x[i] remains a high-precedence-application to a list expression

I expect we could make a transformation in the parse phase to change this to an indexing/slicing node in SyntaxTree. Currently this transformation is done in CheckExpressions.fs. I'm not too fussed either way, but once I'm confident the technique works I'll likely move to the former.

@dsyme
Copy link
Contributor Author

dsyme commented Jul 5, 2021

This hits some compatibility and/or completeness problems on compound expressions , e.g. consider that this F# code is allowed today:

let g a b = a, b   // val g : a:'a -> b:'b -> 'a * 'b

let f (arr:int[])  = g (arr)[4];;

Here (arr)[4] doesn't count as a "high precedence application" for existing F# code, and the application of g is to two curried arguments as if it had been written with a space:

let f (arr:int[])  = g (arr) [4];;

The "high precedence application" limitation only kicks in for identifiers, e.g. the following F# code is disallowed today:

let f (arr:int[])  = g arr[4];;

To maintain compatibility here and still allow indexer notation on a non-identifier left-hand-expression in argument position is not going to be possible. This will affect indexing of all these forms:

g (f())[i]
g (arr)[i]
g arr[i][j]
g (arr[i])[j]
g arr[*][i]

and so on, especially if used in argument position in a curried function. Ideally we would require that people change

let f (arr:int[])  = g (some-expr)[4];;

to this, with the space:

let f (arr:int[])  = g (some-expr) [4];;

However that is intrusive on existing code. We could say that compound indexing is not allowed or must use .[idx], though that would be very unfortunate.

@Swoorup
Copy link
Contributor

Swoorup commented Jul 27, 2021

I always preferred the dot syntax rather than just in arr[idx], as it was easily greppable and a place for potential issues.

@dsyme
Copy link
Contributor Author

dsyme commented Jul 27, 2021

I always preferred the dot syntax rather than just in arr[idx], as it was easily greppable and a place for potential issues.

Yes, I understand there are advantages, and it is likely existing F# programmers (and functional programmers in general) are happy with arr.[idx].

However we get a lot of feedback from anyone coming from C#, Python, Java (99% of world's programmers) that this is just very unusual. I do think it interferes with learning.

We can discuss on RFC.

@dsyme
Copy link
Contributor Author

dsyme commented Jul 27, 2021

Continued at #11900

@dsyme dsyme closed this Jul 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants