caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* obj.magic for polymorphic record fields
@ 2009-12-20 17:44 Jacques Le Normand
  2009-12-20 18:17 ` [Caml-list] " Nicolas Pouillard
  0 siblings, 1 reply; 8+ messages in thread
From: Jacques Le Normand @ 2009-12-20 17:44 UTC (permalink / raw)
  To: caml-list caml-list

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

Dear ocaml-list,
the following code does not type check:

type foo = {bar : 'a. 'a -> 'a}
let a : int -> int = fun x -> x
let baz = {bar = Obj.magic a}

with the error

Error: This field value has type 'a -> 'a which is less general than
         'b. 'b -> 'b


my question is: how could I use obj.magic to get a polymorphic type?


Jacques

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

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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-20 17:44 obj.magic for polymorphic record fields Jacques Le Normand
@ 2009-12-20 18:17 ` Nicolas Pouillard
  0 siblings, 0 replies; 8+ messages in thread
From: Nicolas Pouillard @ 2009-12-20 18:17 UTC (permalink / raw)
  To: Jacques Le Normand; +Cc: caml-list caml-list

Excerpts from Jacques Le Normand's message of Sun Dec 20 18:44:57 +0100 2009:
> Dear ocaml-list,
> the following code does not type check:
> 
> type foo = {bar : 'a. 'a -> 'a}
> let a : int -> int = fun x -> x
> let baz = {bar = Obj.magic a}
> 
> with the error
> 
> Error: This field value has type 'a -> 'a which is less general than
>          'b. 'b -> 'b
> 
> 
> my question is: how could I use obj.magic to get a polymorphic type?

Apart from the traditional
  "You should avoid Obj.magic as much as possible!"

I once faced this situation and the solution is to use modules.

module M : sig
  val f : 'a -> 'a
end = struct
  let f = Obj.magic
end ;;
let baz = {bar = M.f };;

Have fun!

-- 
Nicolas Pouillard
http://nicolaspouillard.fr


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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-22 21:49       ` Boris Yakobowski
@ 2009-12-24 12:10         ` Goswin von Brederlow
  0 siblings, 0 replies; 8+ messages in thread
From: Goswin von Brederlow @ 2009-12-24 12:10 UTC (permalink / raw)
  To: boris; +Cc: caml-list caml-list

Boris Yakobowski <boris@yakobowski.org> writes:

> On Tue, Dec 22, 2009 at 2:35 PM, Goswin von Brederlow <goswin-v-b@web.de> wrote:
>> But the type inference should deduce that in
>>
>> (Obj.magic fn) x
>>
>> the 'a is actually 'b -> 'c as I am applying an argument to it.
>
> Sure, and it does. But it remains that the principal type of
> (Obj.magic fn) is 'a, without any other constraint on 'a. The fact
> that you use it with type 'b -> 'c for some 'b and 'c is irrelevant,
> and the type-checker can safely draw conclusions from the principal
> type. (This is similar to considering List.map (fun x -> x). It has
> type 'a list -> 'a list, even though it is used with type int list ->
> int list if you apply it to [1].)
>
> Hope this helps,
>
> -- 
> Boris

Nope.

# Obj.magic;;
- : 'a -> 'b = <fun>

# let id x = x;;
val id : 'a -> 'a = <fun>

# let f x y = (id x) y;;
val f : ('a -> 'b) -> 'a -> 'b = <fun>

The type checker inferes correctly that the 'a in id must actualy be
('a -> 'b) and gives that type to x.

# let g x y = (Obj.magic x) y;;
Warning X: this argument will not be used by the function.
val g : 'a -> 'b -> 'c = <fun>

No such luck here.

I think the difference is that in Obj.magic there is no connection
between the input ('a) and the output ('b). Something I think only
Obj.magic has. So the type inference can not infere that the 'a in g
must be of type ('d -> 'e) where 'd is compatible with 'b and 'e
compatible with 'c (as in it doesn't segfault).

Maybe there should be a special Obj.less_magic that preserves the
number of arguments between input and output type. Obj.less_magic
could only have types

'a               -> 'b
('a -> 'b)       -> ('c -> 'd)
('a -> 'b -> 'c) -> ('d -> 'e -> 'f)
...

That would be something that needs to be hardcoded into the type
inference or needs a new type syntax. But it would give verry little
extra security. Obj.magic just is evil. :)

MfG
        Goswin


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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-22 13:35     ` Goswin von Brederlow
@ 2009-12-22 21:49       ` Boris Yakobowski
  2009-12-24 12:10         ` Goswin von Brederlow
  0 siblings, 1 reply; 8+ messages in thread
From: Boris Yakobowski @ 2009-12-22 21:49 UTC (permalink / raw)
  To: Goswin von Brederlow, caml-list caml-list

On Tue, Dec 22, 2009 at 2:35 PM, Goswin von Brederlow <goswin-v-b@web.de> wrote:
> But the type inference should deduce that in
>
> (Obj.magic fn) x
>
> the 'a is actually 'b -> 'c as I am applying an argument to it.

Sure, and it does. But it remains that the principal type of
(Obj.magic fn) is 'a, without any other constraint on 'a. The fact
that you use it with type 'b -> 'c for some 'b and 'c is irrelevant,
and the type-checker can safely draw conclusions from the principal
type. (This is similar to considering List.map (fun x -> x). It has
type 'a list -> 'a list, even though it is used with type int list ->
int list if you apply it to [1].)

Hope this helps,

-- 
Boris


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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-21 14:00   ` Boris Yakobowski
  2009-12-21 16:05     ` Jacques Le Normand
@ 2009-12-22 13:35     ` Goswin von Brederlow
  2009-12-22 21:49       ` Boris Yakobowski
  1 sibling, 1 reply; 8+ messages in thread
From: Goswin von Brederlow @ 2009-12-22 13:35 UTC (permalink / raw)
  To: boris; +Cc: Goswin von Brederlow, Damien Guichard, caml-list caml-list

Boris Yakobowski <boris@yakobowski.org> writes:

> On Mon, Dec 21, 2009 at 2:44 PM, Goswin von Brederlow <goswin-v-b@web.de> wrote:
>>> However it issues a warning so i acknowledge it's less elegant.
>>
>> Which I don't quite understand.
>
> The warning is based on the results of the type inference algorithm.
> You're not supposed to find values of type 'a. 'a "in the wild", yet
> (Obj.magic a) has this type. Thus the Ocaml compiler deduces that
> you're doing something wrong: your function never returns, it does not
> use its arguments, etc. Here, using Obj.magic breaks the crystal ball
> of the compiler, and the warning is incorrect.
>
> There is an easy way to silence the warning though:
>
> let baz = {bar = fun x -> (Obj.magic a : _ -> _) x}
>
> (but not let baz = {bar = fun x -> (Obj.magic a : 'a -> 'a) x} for
> ugly reasons...)
>
> You are however quite correct. Using Obj.magic in this particular case
> seems quite wrong.
>
> -- 
> Boris

But the type inference should deduce that in

(Obj.magic fn) x

the 'a is actually 'b -> 'c as I am applying an argument to it.
Seems to me there is something special for Obj.magic so it doesn't
automatically cast values to functions.

MfG
        Goswin


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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-21 14:00   ` Boris Yakobowski
@ 2009-12-21 16:05     ` Jacques Le Normand
  2009-12-22 13:35     ` Goswin von Brederlow
  1 sibling, 0 replies; 8+ messages in thread
From: Jacques Le Normand @ 2009-12-21 16:05 UTC (permalink / raw)
  To: boris; +Cc: Goswin von Brederlow, caml-list caml-list, Damien Guichard

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

right, the use case is totally wrong
I'm automatically generating code from type declarations using camlp4 and it
would break down in presence of polymorphic record fields.

Here's the fix I chose (Thanks to Mr. Pouillard):

module type MagicSignature =
sig
  val x : 'a
end

and I would replace every occurence of

{bar = x}

with

let module X : MagicSignature = (struct let y = x end) in {bar = X.y}

-Jacques L.

On Mon, Dec 21, 2009 at 9:00 AM, Boris Yakobowski <boris@yakobowski.org>wrote:

> On Mon, Dec 21, 2009 at 2:44 PM, Goswin von Brederlow <goswin-v-b@web.de>
> wrote:
> >> However it issues a warning so i acknowledge it's less elegant.
> >
> > Which I don't quite understand.
>
> The warning is based on the results of the type inference algorithm.
> You're not supposed to find values of type 'a. 'a "in the wild", yet
> (Obj.magic a) has this type. Thus the Ocaml compiler deduces that
> you're doing something wrong: your function never returns, it does not
> use its arguments, etc. Here, using Obj.magic breaks the crystal ball
> of the compiler, and the warning is incorrect.
>
> There is an easy way to silence the warning though:
>
> let baz = {bar = fun x -> (Obj.magic a : _ -> _) x}
>
> (but not let baz = {bar = fun x -> (Obj.magic a : 'a -> 'a) x} for
> ugly reasons...)
>
> You are however quite correct. Using Obj.magic in this particular case
> seems quite wrong.
>
> --
> Boris
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> 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: 2799 bytes --]

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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-21 13:44 ` Goswin von Brederlow
@ 2009-12-21 14:00   ` Boris Yakobowski
  2009-12-21 16:05     ` Jacques Le Normand
  2009-12-22 13:35     ` Goswin von Brederlow
  0 siblings, 2 replies; 8+ messages in thread
From: Boris Yakobowski @ 2009-12-21 14:00 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: Damien Guichard, caml-list caml-list

On Mon, Dec 21, 2009 at 2:44 PM, Goswin von Brederlow <goswin-v-b@web.de> wrote:
>> However it issues a warning so i acknowledge it's less elegant.
>
> Which I don't quite understand.

The warning is based on the results of the type inference algorithm.
You're not supposed to find values of type 'a. 'a "in the wild", yet
(Obj.magic a) has this type. Thus the Ocaml compiler deduces that
you're doing something wrong: your function never returns, it does not
use its arguments, etc. Here, using Obj.magic breaks the crystal ball
of the compiler, and the warning is incorrect.

There is an easy way to silence the warning though:

let baz = {bar = fun x -> (Obj.magic a : _ -> _) x}

(but not let baz = {bar = fun x -> (Obj.magic a : 'a -> 'a) x} for
ugly reasons...)

You are however quite correct. Using Obj.magic in this particular case
seems quite wrong.

-- 
Boris


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

* Re: [Caml-list] obj.magic for polymorphic record fields
  2009-12-20 18:45 Re[2]: " Damien Guichard
@ 2009-12-21 13:44 ` Goswin von Brederlow
  2009-12-21 14:00   ` Boris Yakobowski
  0 siblings, 1 reply; 8+ messages in thread
From: Goswin von Brederlow @ 2009-12-21 13:44 UTC (permalink / raw)
  To: Damien Guichard; +Cc: caml-list caml-list

"Damien Guichard" <alphablock@orange.fr> writes:

>> I once faced this situation and the solution is to use modules.
> That is one good practical solution.
>
> The simpler solution that immediatly came to my mind is eta-expansion.
>
>   type foo = {bar : 'a. 'a -> 'a}
>   let a : int -> int = fun x -> x
>   let baz = {bar = fun x -> (Obj.magic a) x}

This would create a new closure though. Wastes time and space. Bad if
you create a million foo's all with the same function.

> However it issues a warning so i acknowledge it's less elegant.

Which I don't quite understand.

> - damien

Why not use magic on the overall type of the record instead of the
individual function?

# type foo = { foo : 'a. 'a -> 'a; }
  type 'a bar = {bar : 'a -> 'a}
  let a : int -> int = fun x -> x
  let baz = (Obj.magic {bar = a} : foo);;

type foo = { foo : 'a. 'a -> 'a; }
type 'a bar = { bar : 'a -> 'a; }
val a : int -> int = <fun>
val baz : foo = {foo = <fun>}

It means duplicating the record type but you can magic it without
warnings.


Overall I have to say though that you are doing something wrong here.
(Should I assume your actual use case is larger than this simple
example?)

# let b x = x + 1
  let buzz = (Obj.magic {bar = b} : foo)
  buzz.foo [1;2;3];;
val b : int -> int = <fun>
val buzz : foo = {foo = <fun>}
- : int list = [-2330612807164231680]

Doesn't always segfault but lets get nastier:

# (buzz.foo buzz).foo 1;;
zsh: segmentation fault  ocaml

The obj.magic only works safely if the function you use is of type 'a
-> 'a (even if the interface restricts it to a less general type). The
right solution would be to loosen the interface to use the more
general type.

MfG
        Goswin


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

end of thread, other threads:[~2009-12-24 12:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-20 17:44 obj.magic for polymorphic record fields Jacques Le Normand
2009-12-20 18:17 ` [Caml-list] " Nicolas Pouillard
2009-12-20 18:45 Re[2]: " Damien Guichard
2009-12-21 13:44 ` Goswin von Brederlow
2009-12-21 14:00   ` Boris Yakobowski
2009-12-21 16:05     ` Jacques Le Normand
2009-12-22 13:35     ` Goswin von Brederlow
2009-12-22 21:49       ` Boris Yakobowski
2009-12-24 12:10         ` Goswin von Brederlow

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).