caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] How to rename a record field
@ 2018-09-06 11:36 Enrico Tassi
  2018-09-06 11:48 ` Gabriel Scherer
  2018-09-06 16:20 ` Alain Frisch
  0 siblings, 2 replies; 12+ messages in thread
From: Enrico Tassi @ 2018-09-06 11:36 UTC (permalink / raw)
  To: caml-list

Dear caml-list, while refining an API I felt the need to rename a record
field. I'd like to be nice to my users and have the API evolve without
breaking compilation but eventually emitting deprecation warnings.

What I'd like to do, concretely is to move from this

  record t = { bad : int; stuff : ty }

to

  record old = { bad : int [@deprecated "use good"]; stuff : ty }
  record t = old = { good : int; stuff : ty }

The last line does not type check since old and good are different
names. What I'd like to obtain is to have bad and good act as synonyms,
and have OCaml generate a warning when bad is used.

This is pretty much what you would do for a function: leave the old one
in place and stick a deprecate attribute to it.

Is there a way to achieve that for records?
  
Best,
-- 
Enrico Tassi

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 11:36 [Caml-list] How to rename a record field Enrico Tassi
@ 2018-09-06 11:48 ` Gabriel Scherer
  2018-09-06 13:03   ` Enrico Tassi
  2018-09-06 16:20 ` Alain Frisch
  1 sibling, 1 reply; 12+ messages in thread
From: Gabriel Scherer @ 2018-09-06 11:48 UTC (permalink / raw)
  To: Enrico Tassi; +Cc: caml users

[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]

A couple years ago I had a similar feature request for variant (sum)
constructors, and Jacques Garrigue explained that it is in fact quite
difficult. (The reasons apply to record fields as well.) I suspect that you
are out of luck.

  MPR#7102: Ability to re-export a variant definition with renamed
constructors?
  https://caml.inria.fr/mantis/view.php?id=7102


On Thu, Sep 6, 2018 at 1:36 PM Enrico Tassi <enrico.tassi@inria.fr> wrote:

> Dear caml-list, while refining an API I felt the need to rename a record
> field. I'd like to be nice to my users and have the API evolve without
> breaking compilation but eventually emitting deprecation warnings.
>
> What I'd like to do, concretely is to move from this
>
>   record t = { bad : int; stuff : ty }
>
> to
>
>   record old = { bad : int [@deprecated "use good"]; stuff : ty }
>   record t = old = { good : int; stuff : ty }
>
> The last line does not type check since old and good are different
> names. What I'd like to obtain is to have bad and good act as synonyms,
> and have OCaml generate a warning when bad is used.
>
> This is pretty much what you would do for a function: leave the old one
> in place and stick a deprecate attribute to it.
>
> Is there a way to achieve that for records?
>
> Best,
> --
> Enrico Tassi
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

[-- Attachment #2: Type: text/html, Size: 2301 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 11:48 ` Gabriel Scherer
@ 2018-09-06 13:03   ` Enrico Tassi
  2018-09-06 13:17     ` Jacques Garrigue
  0 siblings, 1 reply; 12+ messages in thread
From: Enrico Tassi @ 2018-09-06 13:03 UTC (permalink / raw)
  To: caml-list

On Thu, Sep 06, 2018 at 01:48:23PM +0200, Gabriel Scherer wrote:
>   MPR#7102: Ability to re-export a variant definition with renamed
> constructors?
>   https://caml.inria.fr/mantis/view.php?id=7102

Thanks for the pointer, but I'm not sure I understand how the arguments
made there apply to records.

My intuition is that, given that records are compared by name, there
should be no difference between adding the equation t = old or
casting (with Obj.magic) each and every term of type old to type t.
To my knowledge the two records have the very same representation at run
time, that does not depend on the names of the fields but just their
types.

I've even tried to disable the check in typing/includecore.ml around
line 230 and the following silly test seems to work.

  type old = { bad : int; stuff : bool }
  type t = old = { good : int; stuff : bool }
  
  let rb = { bad = 3; stuff = false }
  let rg = { good = 3; stuff = false }
  
  let _ = Printf.printf "%b\n" rb.stuff
  let _ = Printf.printf "%b\n" rg.stuff
  let _ = Printf.printf "%d\n" rb.bad
  let _ = Printf.printf "%d\n" rg.good
  let _ = Printf.printf "%d\n" rg.bad
  let _ = Printf.printf "%d\n" rb.good
  let _ = Printf.printf "%d\n" { rb with good = rb.bad + 1 }.bad
  let _ = Printf.printf "%b\n" { rb with stuff = not rg.stuff }.stuff

Where is my intuition wrong?

Why records needs to be compared by name and not by (type) structure?
Sorry if the question is silly, but I really don't know.

Best,
-- 
Enrico Tassi

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 13:03   ` Enrico Tassi
@ 2018-09-06 13:17     ` Jacques Garrigue
  2018-09-06 14:18       ` Enrico Tassi
  0 siblings, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2018-09-06 13:17 UTC (permalink / raw)
  To: Enrico Tassi; +Cc: Mailing List OCaml

On 2018/09/06 22:03, Enrico Tassi wrote:
> 
> On Thu, Sep 06, 2018 at 01:48:23PM +0200, Gabriel Scherer wrote:
>>  MPR#7102: Ability to re-export a variant definition with renamed
>> constructors?
>>  https://caml.inria.fr/mantis/view.php?id=7102
> 
> Thanks for the pointer, but I'm not sure I understand how the arguments
> made there apply to records.

Records being the dual of variants, all the arguments apply.
Namely, if the name is allowed to change, field access can no longer
be seen as the intuitive projection (by name rather than position, since
only name information is available in the source code).
Field name disambiguation works in the same way too.

There is also the same problem with GADTs assuming that two
record types with different field names are distictinct.

The fact the representation is identical is just an implementation detail.
Tuples too share the same representation.

Jacques Garrigue

> My intuition is that, given that records are compared by name, there
> should be no difference between adding the equation t = old or
> casting (with Obj.magic) each and every term of type old to type t.
> To my knowledge the two records have the very same representation at run
> time, that does not depend on the names of the fields but just their
> types.
> 
> I've even tried to disable the check in typing/includecore.ml around
> line 230 and the following silly test seems to work.
> 
>  type old = { bad : int; stuff : bool }
>  type t = old = { good : int; stuff : bool }
> 
>  let rb = { bad = 3; stuff = false }
>  let rg = { good = 3; stuff = false }
> 
>  let _ = Printf.printf "%b\n" rb.stuff
>  let _ = Printf.printf "%b\n" rg.stuff
>  let _ = Printf.printf "%d\n" rb.bad
>  let _ = Printf.printf "%d\n" rg.good
>  let _ = Printf.printf "%d\n" rg.bad
>  let _ = Printf.printf "%d\n" rb.good
>  let _ = Printf.printf "%d\n" { rb with good = rb.bad + 1 }.bad
>  let _ = Printf.printf "%b\n" { rb with stuff = not rg.stuff }.stuff
> 
> Where is my intuition wrong?
> 
> Why records needs to be compared by name and not by (type) structure?
> Sorry if the question is silly, but I really don't know.
> 
> Best,




-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 13:17     ` Jacques Garrigue
@ 2018-09-06 14:18       ` Enrico Tassi
  2018-09-06 23:34         ` Jacques Garrigue
  0 siblings, 1 reply; 12+ messages in thread
From: Enrico Tassi @ 2018-09-06 14:18 UTC (permalink / raw)
  To: caml-list

On Thu, Sep 06, 2018 at 10:17:25PM +0900, Jacques Garrigue wrote:
> Records being the dual of variants, all the arguments apply.
> Namely, if the name is allowed to change, field access can no longer
> be seen as the intuitive projection (by name rather than position, since
> only name information is available in the source code).
> Field name disambiguation works in the same way too.

Thanks. I see why in the general case this makes the source code
ambiguous.

> >  type old = { bad : int; stuff : bool }
> >  type t = old = { good : int; stuff : bool }

But in a case as simple as this one where names are either different
or occur in the same position I believe there is no ambiguity.
"stuff" would always resolve to position 2 while both
"good" and "bad" to position 1.

I'm not knowledgeable enough to follow your reasoning about GADTs.
Maybe the approach I propose is really unsound, even if I fail to get
it. Still I believe the use case (renaming + deprecating a record field)
is relevant. Any other approach (especially not requiring to patch OCaml)
would make me happy.

Best,
-- 
Enrico Tassi

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 11:36 [Caml-list] How to rename a record field Enrico Tassi
  2018-09-06 11:48 ` Gabriel Scherer
@ 2018-09-06 16:20 ` Alain Frisch
  2018-09-06 16:21   ` Alain Frisch
  1 sibling, 1 reply; 12+ messages in thread
From: Alain Frisch @ 2018-09-06 16:20 UTC (permalink / raw)
  To: Enrico Tassi, caml-list

On 06/09/2018 13:36, Enrico Tassi wrote:
> Dear caml-list, while refining an API I felt the need to rename a record
> field. I'd like to be nice to my users and have the API evolve without
> breaking compilation but eventually emitting deprecation warnings.

If you could go back in time, the best solution might be to avoid 
exposing a concrete record type, but rather a constructor function (and 
possibly deconstructors, if needed).  Thanks to optional arguments in 
particular, this enables a smoother experience for evolving the API 
(e.g. by adding new fields, with a natural default value).

Btw, it might be interesting to allow deprecating the presence or 
absence of fields.

-- Alain

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 16:20 ` Alain Frisch
@ 2018-09-06 16:21   ` Alain Frisch
  2018-09-06 23:45     ` Jacques Garrigue
  0 siblings, 1 reply; 12+ messages in thread
From: Alain Frisch @ 2018-09-06 16:21 UTC (permalink / raw)
  To: Enrico Tassi, caml-list

On 06/09/2018 18:20, Alain Frisch wrote:
> Btw, it might be interesting to allow deprecating the presence or 
> absence of fields.

Sorry, I meant the presence or absence of *optional arguments*, of course.

-- Alain

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 14:18       ` Enrico Tassi
@ 2018-09-06 23:34         ` Jacques Garrigue
  0 siblings, 0 replies; 12+ messages in thread
From: Jacques Garrigue @ 2018-09-06 23:34 UTC (permalink / raw)
  To: Enrico Tassi; +Cc: Mailing List OCaml

On 2018/09/06 23:18, Enrico Tassi wrote:
> 
> On Thu, Sep 06, 2018 at 10:17:25PM +0900, Jacques Garrigue wrote:
>> Records being the dual of variants, all the arguments apply.
>> Namely, if the name is allowed to change, field access can no longer
>> be seen as the intuitive projection (by name rather than position, since
>> only name information is available in the source code).
>> Field name disambiguation works in the same way too.
> 
> Thanks. I see why in the general case this makes the source code
> ambiguous.
> 
>>> type old = { bad : int; stuff : bool }
>>> type t = old = { good : int; stuff : bool }
> 
> But in a case as simple as this one where names are either different
> or occur in the same position I believe there is no ambiguity.
> "stuff" would always resolve to position 2 while both
> "good" and "bad" to position 1.


Suppose that (maybe in another module) you have

   type u = old = {bad : int; good : bool }

Now, a piece of code containing

        x.good

could mean either (x : old).bad or (x : old).stuff, with x having a type
compatible with both t and u simultaneously.

Here it happens that int and bool being incompatible, a wrong interpretation
would probably cause an error somewhere, but this looks rather unpredictable.
Worse, in ocaml it is not always decidable whether two types might be equal
or not, so a definition time restriction could be hard to predict too.

Jacques Garrigue

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 16:21   ` Alain Frisch
@ 2018-09-06 23:45     ` Jacques Garrigue
  2018-09-07  8:36       ` Alain Frisch
  0 siblings, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2018-09-06 23:45 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Enrico Tassi, Mailing List OCaml

On 2018/09/07 01:21, Alain Frisch wrote:
> 
> On 06/09/2018 18:20, Alain Frisch wrote:
>> Btw, it might be interesting to allow deprecating the presence or absence of fields.
> 
> Sorry, I meant the presence or absence of *optional arguments*, of course.


Interesting idea.
This should be easily doable, for instance by extending the Asttypes.arg_label type.
By deprecating the absence, do you mean having a warning when the argument is ommited?
Wouldn’t it mean having two distinct deprecation annotations for optional arguments?

Jacques

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-06 23:45     ` Jacques Garrigue
@ 2018-09-07  8:36       ` Alain Frisch
  2018-09-07 10:13         ` Jacques Garrigue
  0 siblings, 1 reply; 12+ messages in thread
From: Alain Frisch @ 2018-09-07  8:36 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: Enrico Tassi, Mailing List OCaml

On 07/09/2018 01:45, Jacques Garrigue wrote:
> Interesting idea.
> This should be easily doable, for instance by extending the Asttypes.arg_label type.

One could also just keep the information on the value binding itself:

   val foo: ?x:int -> ?y:float-> int -> int
      [@@ocaml.deprecated_argument x "Please use y instead!"]
      [@@ocaml.deprecated_missing_argument x "Please pass y, it will 
soon be mandatory"]


Or indeed allow adding attributes on (labeled?) arguments, or interpret 
attributes on their types.  But internally, the information could always 
be attached to the value binding, which should be simpler than storing 
it in the type.

> By deprecating the absence, do you mean having a warning when the argument is ommited?
> Wouldn’t it mean having two distinct deprecation annotations for optional arguments?

Yes, of course.  "Old" attributes (that will be discarded at some point) 
should be reported when they are passed a value; "new" attributes (that 
might become non-optional) should be reported when they are omitted.  It 
remains to be seen what to do with applications with the ?x syntax (i.e. 
passing an option).


Alain

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-07  8:36       ` Alain Frisch
@ 2018-09-07 10:13         ` Jacques Garrigue
  2018-09-07 12:49           ` Alain Frisch
  0 siblings, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2018-09-07 10:13 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Mailing List OCaml

On 2018/09/07 17:36, Alain Frisch wrote:
> 
> On 07/09/2018 01:45, Jacques Garrigue wrote:
>> Interesting idea.
>> This should be easily doable, for instance by extending the Asttypes.arg_label type.
> 
> One could also just keep the information on the value binding itself:
> 
>  val foo: ?x:int -> ?y:float-> int -> int
>     [@@ocaml.deprecated_argument x "Please use y instead!"]
>     [@@ocaml.deprecated_missing_argument x "Please pass y, it will soon be mandatory"]
> 
> 
> Or indeed allow adding attributes on (labeled?) arguments, or interpret attributes on their types.  But internally, the information could always be attached to the value binding, which should be simpler than storing it in the type.

This is not so clear. 
The binding information could be hard to bring to the application type inference, while if it is contained in the label, it is already available where it is needed.

Also, attaching  the deprecation to the binding means that we can only refer to the first optional argument with the same name. In theory, there could be several, but I agree that this is going to be extremely rare.

>> By deprecating the absence, do you mean having a warning when the argument is ommited?
>> Wouldn’t it mean having two distinct deprecation annotations for optional arguments?
> 
> Yes, of course.  "Old" attributes (that will be discarded at some point) should be reported when they are passed a value; "new" attributes (that might become non-optional) should be reported when they are omitted.  It remains to be seen what to do with applications with the ?x syntax (i.e. passing an option).


I suppose ?x should raise a warning too, since it is intended to allow both pasing and not passing, and one of the two is wrong.

Jacques

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] How to rename a record field
  2018-09-07 10:13         ` Jacques Garrigue
@ 2018-09-07 12:49           ` Alain Frisch
  0 siblings, 0 replies; 12+ messages in thread
From: Alain Frisch @ 2018-09-07 12:49 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: Mailing List OCaml

On 07/09/2018 12:13, Jacques Garrigue wrote:
> On 2018/09/07 17:36, Alain Frisch wrote:
>> Or indeed allow adding attributes on (labeled?) arguments, or interpret attributes on their types.  But internally, the information could always be attached to the value binding, which should be simpler than storing it in the type.
> 
> This is not so clear.
> The binding information could be hard to bring to the application type inference, while if it is contained in the label, it is already available where it is needed.

Do you have in mind really tracking the annotation during type 
inference?  For instance, to support binding a partial application of a 
function, and still track the deprecation of arguments of the resulting 
function?

I was thinking about a much more limited approach: the deprecation of 
arguments is checked when the functional value is referenced and 
immediately applied.

Quick POC to track the discussion on this topic: 
https://github.com/ocaml/ocaml/pull/2027


Alain

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-09-07 12:50 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-06 11:36 [Caml-list] How to rename a record field Enrico Tassi
2018-09-06 11:48 ` Gabriel Scherer
2018-09-06 13:03   ` Enrico Tassi
2018-09-06 13:17     ` Jacques Garrigue
2018-09-06 14:18       ` Enrico Tassi
2018-09-06 23:34         ` Jacques Garrigue
2018-09-06 16:20 ` Alain Frisch
2018-09-06 16:21   ` Alain Frisch
2018-09-06 23:45     ` Jacques Garrigue
2018-09-07  8:36       ` Alain Frisch
2018-09-07 10:13         ` Jacques Garrigue
2018-09-07 12:49           ` Alain Frisch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).