-
Notifications
You must be signed in to change notification settings - Fork 21
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
un-deprecate unused parameters in type abbreviations #597
Comments
@A-Manning Could you give a couple of detailed examples please? Many thanks |
One example would be to express a relation of something to another type;
All of the functions in the module defining Related are going to have to add and remove the R constructor a lot, whereas they wouldn't if These types occur frequently in F* code (where the unused parameter is erased), and can't extract to F# correctly because of this restriction - so I suppose another example would be if we want to use F# to implement dependently typed languages. For example, I might want to have a type of arrays indexed by their length, as Perhaps this should just generate a warning, rather than an error? |
Another use of types of this form is to express OCaml-style phantom types. |
This is a pretty neat trick! |
One of my coworkers has a version of F# Compiler Services that gives warnings rather than errors for this, here zenprotocol/FSharp.Compiler.Service@1201088 |
There are technical reasons why this wasn't allowed in F# - though you could argue about their importance, and it depends what features of F# and .NET you use For example, consider
Does the compiled form of There may be ways to navigate this technical difficulty but I'm not sure, and it may be very subtle, involving extensive type annotations. There are some similarities to units of measure inference, for example. Of course, if you never rely on the type passing capabilities of F# (don't use |
Thanks for your response! I think it's ok if For F* interop with F#, this is an annoying and pervasive issue, since allowing type-level functions and higher types means that I can write type const 'a 'b : Type = 'a which would have to extract to type const<'a, 'b> = 'a This pops up frequently in extracted F* code, and has to be handled manually somehow (this is not always possible), which is not fun! I don't think that there is much that can be done to prevent types like this from being extracted, unless it's possible to pull some tricks with measure types. OCaml allows this form of type definition, which makes it much more stable as an extraction target for F*. What would the issues with binary compiled form be? |
Basically the same - would the C# consumer see a generic method or not, and if so how many type parameters The F# compiler freely eliminates type abbreviations wherever it wants - so I'm not actually sure what would happen with things like
I assume it would be treated as the equivalent of
which is a non-generic function, and give a warning that |
@dsyme What do you think is the right solution then? If this is added to F#, users might have surprising issues when making use of type passing. If this is not, then there will continue to be issues with F* interop, and most likely a fork of F# will need to be maintained specifically for F*. Should this be allowed with warnings rather than errors? Should the compiler have a flag to allow this? Or should this be maintained as a fork?
I'd be happy to work on a more sophisticated workaround, but I'm not sure what would need to be done. I'd be happy to discuss this further. |
@A-Manning I'm not sure there is a solution :) That's why we made this an error. One way to move forward would be for you to change the error to a warning in a branch of your own, and recruit/hassle/invite/bribe people to work out what happens in various corner cases like the ones above (and find even more challenging versions), and write that up here? |
What about we allow this provided the unused type parameters have an attribute |
Yes. We could probably infer that without even needing any attribute, though in general having a notion of |
Has there been any movement on this? Seems like you guys sort of agreed on a possible way forward. |
@ChechyLevas My bad, I seem to have let this slip - I'll make a branch that uses the |
I'm closing this as it's not often requested and the above discussion shows it's technically challenging |
I actually think this is fairly straightforward: type X<'T> = int
let f0 (x: int) = x // not generic
let f1 (x: X<'T>) = x // compiled form has unused generic type parameter
let f2 (x: int) = (x: X<'T>) // not generic - gives warning that 'T has been instantiated to obj
let f3 (x: X<'T>) = typeof<'T> // compiled form has generic type parameter
let f4 (x: X<string>) = x // not generic - compiled form is equivalent to f0
@dsyme Do you have any objection to the above? I'd be happy to implement it. I still think there might be value in an |
I propose we allow unused parameters in type abbreviations.
As it stands,
type t<'a,'b> = 'a
gives an error:Type abbreviations of this form can be very useful in enforcing abstractions through
abstract
,private
, etc. Type abbreviations of this form are allowed in OCaml.The existing way of approaching this problem in F# is to either use a constructor, as in
type t<'a,'b> = C of 'a
, or sometimes use hacks with measure types. This seems unnecessary and burdensome.Pros and Cons
The advantages of making this adjustment to F# are that it would be easier to use these types for abstraction. The construct was previously allowed, so this is unlikely to require significant changes.
The disadvantages of making this adjustment to F# are that perhaps this could be seen as obfuscatory? I think such definitions are clear though. Unused parameters are allowed in function definitions, so why not type abbreviations?
Extra information
Estimated cost XS: Since F# allowed this in the past, it doesn't seem that it should be too hard to bring this back.
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
The text was updated successfully, but these errors were encountered: