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

Duplicated record names in distinct types #4172

Closed
vicuna opened this issue Nov 27, 2006 · 4 comments
Closed

Duplicated record names in distinct types #4172

vicuna opened this issue Nov 27, 2006 · 4 comments
Assignees

Comments

@vicuna
Copy link

vicuna commented Nov 27, 2006

Original bug ID: 4172
Reporter: acone
Assigned to: @pierreweis
Status: closed (set by @alainfrisch on 2014-02-17T15:44:20Z)
Resolution: fixed
Priority: normal
Severity: feature
Category: ~DO NOT USE (was: OCaml general)
Related to: #5525

Bug description

In OCaml, the following causes problems:

type t1 = {a:int; b:int}
type t2 = {a:string; c:string}
let make_t1() = {a=5; b=10}

It's clear to our eyes that make_t1 should return a t1, not a t2, but the compiler assumes that it returns a t2. It does this because I've used a label that's bound in t2 (namely 'a'), and t2 was declared later. So when I run this code I get a type error.

I understand that the compiler does not try to infer which of t1 or t2 is meant because this requires exponential time. I admit that exponential time is unacceptable, but I feel there are better solutions than simply defaulting to the most recently declared type.

  1. (the slighly less crappy solution)
    warn the user whenever a parameter in a record type declaration shadows a parameter in a previous record type declaration.

  2. (the solution I'd prefer)
    whenever an expression's type is not uniquely specified by parameter names, require the user to state it's type explicitly.
    For example, the following would be allowed:

type t1 = {a:int; b:int}
type t2 = {a:string; b:string}
let print_t1 (x : t1) = printf "(%d, %d)" x.a x.b

But the following would produce an error message like "Expression type can not be determined from parameter names. Please state its type explicitly.":

type t1 = {a:int; b:int}
type t2 = {a:string; b:string}
let print_t1 x = printf "(%d, %d)" x.a x.b

It should not insist, as it currently does, that I wanted x to be a t2.

Additional information

As it stands, the lack of this feature is a reason I sometimes avoid Caml. The standard solution--to prefix each parameter with the type's name--results in ugly, unreadable code.

The fix I'm proposing would not affect the computational complexity of type inference. It would simply require explicit typing for expressions that should need it.

@vicuna
Copy link
Author

vicuna commented Apr 15, 2007

Comment author: @pierreweis

The general solution to the problem you mentioned is general overloading, and this is well-known as a difficult feature in the context of type inference.

Unfortunately, none of the solutions you proposed are satisfactory:

  • ``solution'' 1) provides a warning to the programmer, which is good but does not solve the problem: you cannot reuse the same label in two distinct types.
  • ``solution'' 2) is not trivial given the current technology of the type-checking and type reconstruction engine.

I'm looking for a different and more general solution to this specific problem.

Paraphrasing the famous Fermat's note on the proof of his conjecture, I would say ``cum grano salis'': I think I have a marvelous solution to this problem, but this bug tracking system is not the place to expose it in detail!

@vicuna
Copy link
Author

vicuna commented Apr 16, 2007

Comment author: @mmottl

My favored solution to this problem is to wrap the record type definitions into a module, e.g. instead of the tedious

type t1 = { t1_field1 : ...; t1_field2 : ... }

you write:

module T1 = struct
type t = { field1 : ...; field2 : ... }
end

Besides being able to just "open T1" to get access to the unprefixed field names of this particular record type, you can also use the following nice syntax for binding record values:

let v =
{ T1.
field1 = ...;
field2 = ...;
}

Hope that helps...

@vicuna
Copy link
Author

vicuna commented Jul 27, 2007

Comment author: jm

instead of the tedious

type t1 = { t1_field1 : ...; t1_field2 : ... }

By the way, for those of us mastering the auto-completion tool of our text editor, this syntax improves our ability to fastly see and write the fields of a record, without our recalling of the doc.
Same thing apply to pattern matching changes/navigations.

let v =
{ T1.
field1 = ...;
field2 = ...;
}
Nice syntax, but not easy to match a given field with a simple regexp.

Moral: the less ambiguous, the better.

@vicuna
Copy link
Author

vicuna commented Feb 12, 2014

Comment author: @yallop

This issue was fixed by the addition of record punning: make_t1 now creates a t1, as expected.

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