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

Warn user when a type variable in a type constraint has been instantiated. #6

Closed
wants to merge 2 commits into from
Closed

Conversation

hnrgrgr
Copy link

@hnrgrgr hnrgrgr commented Jan 31, 2014

It seems to be a common misunderstanding amongst beginners that type variables in type constraint are unification variables and that they should be explicitly quantified when desired.

This small patch adds a warning when such non-quantified variable has been instantiated by the type checker. The verification is made /a posteriori/ by looking for type constraints in the typed tree.

I'm not sure this warning is really a desired feature, but it is probably worth discussion. For instance, ocamlyacc-generated files use such variables on purpose.

@gasche
Copy link
Member

gasche commented Jan 31, 2014

If we accepted '_a in programs and didn't warn on those, we could enable the warning for everyone -- and progressively convert codebases to use '_a for non-generalized inference variables. With the current practices it seems hard to enable the warning except in constrained educational settings, but I think it's still good to have it around.

@trefis
Copy link
Contributor

trefis commented Jan 31, 2014

@gasche do you know why '_a is not accepted?

With the current practices it seems hard to enable the warning except in constrained educational settings

I disagree. I'd be surprised to see people use 'a while expecting it to be unified with int.

I really like the idea of this PR btw!

@gasche
Copy link
Member

gasche commented Jan 31, 2014

Let's formulate this differently: you cannot willingly forget 20 years of (admittedly dubious but voluntary) flexible variable semantics and claim that it's actually a mistake to use them that way. It may seem surprising to you but some people are familiar with the current semantics of type variables and have used it in their codebases -- note that there is no alternative, while it is now possible to explicitly enforce rigid variables with ('a . ...). There even are people that consider the current flexible semantics is the right default.
Warnings are generally used to deprecate a feature, send a signal that "from now on you should avoid that" -- unused variables, (or), resolution of ambiguous record labels by the shadowing rule. It is not possible in this case, or rather would severely restrict expressivity of type annotations. In absence of an alternative to avoid the warning when flexible named variables is what you want, it should be considered not a general recommendation for all codebases, but a specialized recommendation for codebases that are simple enough to not need that -- educational purposes.

I like the idea as well. I did a code review but, besides the universal pattern Thomas spotted already, I couldn't comment much, as I'm not familiar with the type-checker codebase. Alain may have more to tell. I wondered whether this should be a delayed check or not, but my understanding is that the implementation only check variables at "safe points" (after checking a toplevel phrase or complete module structure) where it is a precondition that all local inference constraints have been solved.

@hnrgrgr
Copy link
Author

hnrgrgr commented Jan 31, 2014

Disabling the warning for type variables like '_a would indeed be consistent with warnings triggered by unused (value) variables. Unfortunatly '_a is already used in pretty-printing of weak type variables.

@lefessan
Copy link
Contributor

lefessan commented Feb 1, 2014

Actually, there would be some consistency in having no warnings on '_a, as such variables indicates that they are actually not polymorphic, and should be eventually instantiated. So, we should accept such variables, and warn, on the contrary, if they are not instantiated, while not warning if they are.

@lpw25
Copy link
Contributor

lpw25 commented Feb 3, 2014

Note that -- because of structural types -- some things can only be expressed in OCaml using unification variables. For example, this (nonsense) function can only be written using unification variables:

# let rec f n (x : < m: 'b. 'b -> 'a > as 'a) =
    if n < 0 then x
    else if n = 0 then f (n - 2) (x#m 5)
    else f (n - 2) (x#m 6.0);;
val f : int -> (< m : 'b. 'b -> 'a > as 'a) -> 'a = <fun>

I'm not sure that we should add a warning which goes off for any possible definition of perfectly valid functions.

I also think, that unification variables are used more often than people think: almost every use of as in a type expression for instance.

My preferred approach to helping people to understand the difference between unification variables and type variables would be to have the compiler accept the syntax:

val id: 'a. 'a -> 'a

for value specifications, and also to print value specifications with that syntax by default. This would mean that type variables were consistently bound in OCaml, and unification variables were consistently unbound.

@lpw25
Copy link
Contributor

lpw25 commented Feb 3, 2014

I think your patch still gives a warning for uses of as like this:

# let rec f (x : < m: int; .. > as 'a) : 'a option =
    if x#m < 0 then None
    else Some x;;
val f : (< m : int; .. > as 'a) -> 'a option = <fun>

which I think are very common.

@hnrgrgr
Copy link
Author

hnrgrgr commented Feb 3, 2014

Indeed, your example should not trigger a warning. I forgot that case, thanks. I have updated the patch to handle this case. Maybe not the best implementation, but it should be sufficient to test.

@lpw25
Copy link
Contributor

lpw25 commented Feb 3, 2014

I think your patch still gives a warning for uses of as like this

Oops, I had only seen the changes to extract_vars, and completely missed the addition of extract_aliases. Your updated patch should be fine for the examples I showed.

@hnrgrgr
Copy link
Author

hnrgrgr commented Feb 3, 2014

Unfortunatly, it isn't.

@hnrgrgr
Copy link
Author

hnrgrgr commented Jul 9, 2014

Here is an updated version, with proper 'scope handling' for aliased variables.

@@ -249,7 +250,7 @@ module MakeIterator(Iter : IteratorArgument) : sig
exp.exp_extra;
begin
match exp.exp_desc with
Texp_ident (path, _, _) -> ()
| Texp_ident (path, _, _) -> ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if I don't like it, the implicit coding rules of the compiler forbid this | and the rule have been enforced in other merge request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many occurrences of '|' on the first branch in the compiler code base. I don't think anyone would complain about this style.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thank you, I'm happy to hear it. I will stop removing them from my patch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If anything, I would complain about the absence of the first |. But I've learned not to complain too much.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, changing just this is more of a concern, as the diff is unnecessary!

stedolan pushed a commit to stedolan/ocaml that referenced this pull request Aug 18, 2015
AltGr pushed a commit to AltGr/ocaml that referenced this pull request Nov 14, 2015
mshinwell referenced this pull request in mshinwell/ocaml Jan 18, 2016
@damiendoligez damiendoligez added this to the 4.04-or-later milestone Jan 27, 2016
@damiendoligez damiendoligez removed this from the 4.04 milestone Aug 3, 2016
@garrigue garrigue self-assigned this Feb 22, 2017
@mshinwell
Copy link
Contributor

@garrigue It's been more than three years since the most recent update of this patch, as far as I can see. Is it going to be merged? If not then I think we should close the pull request until someone steps forward to bring the code to a mergeable state.

@garrigue
Copy link
Contributor

We are not going to introduce this change, as it is not "backward compatible" (i.e., doesn't fit well with the existing codebase).
But we're still reflecting on improvements to the handling of type variables.

This was referenced Mar 14, 2019
jfehrle added a commit to jfehrle/ocaml that referenced this pull request Aug 6, 2020
gretay-js pushed a commit to gretay-js/ocaml that referenced this pull request May 28, 2021
Emit low-level location information for FDO: use discriminators (2/2)
punchagan pushed a commit to punchagan/ocaml that referenced this pull request Feb 23, 2022
Add units for metrics and switch to v2 schema
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.

None yet