Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0005361OCamlOCaml generalpublic2011-09-26 01:272012-01-25 23:12
ReporterPascal Cuoq 
Assigned To 
PrioritynormalSeverityfeatureReproducibilityalways
StatusconfirmedResolutionopen 
PlatformOSOS Version
Product Version3.12.1 
Target VersionFixed in Version 
Summary0005361: Syntax to specify that a custom type is never a float
DescriptionConsider the following module:

let f (a: Z.t array) =
  a.(7)

where Z.t is the custom type of integers as implemented by http://forge.ocamlcore.org/projects/zarith/ [^]

You may expect function f to be compiled to:

_camlT__f_1030:
        subl $12, %esp
L100:
        movl -4(%eax), %ebx
        shrl $9, %ebx
        cmpl $15, %ebx
        jbe L101
        movl 28(%eax), %eax
        addl $12, %esp
        ret
L101: call _caml_ml_array_bound_error

(this is on IA32 but the target architecture is not relevant to this discussion)

Unfortunately, in order to obtain the code above, it is necessary to cheat:


$ svn diff z.ml*p
Index: z.mlip
===================================================================
--- z.mlip (revision 43)
+++ z.mlip (working copy)
@@ -41,7 +41,8 @@
 
 (** {1 Types} *)
 
-type t
+type abst
+type t = private A | B of abst
 (** Type of integers of arbitrary length. *)
 
 exception Overflow
Index: z.mlp
===================================================================
--- z.mlp (revision 43)
+++ z.mlp (working copy)
@@ -16,7 +16,8 @@
 
  *)
 
-type t
+type abst
+type t = private A | B of abst
 
 exception Overflow
 
Without the above unsafe changes, the code generated for f is:

_camlT__f_1030:
    subl $12, %esp
L101:
    movl %eax, %ecx
    movl -4(%ecx), %eax
    movl %eax, %ebx
    andl $255, %ebx
    cmpl $254, %ebx
    je L100
    shrl $9, %eax
    cmpl $15, %eax
    jbe L102
    movl 28(%ecx), %eax
    addl $12, %esp
    ret
    .align 4
L100:
    shrl $10, %eax
    cmpl $15, %eax
    jbe L102
L103: movl _caml_young_ptr, %eax
    subl $12, %eax
    movl %eax, _caml_young_ptr
    cmpl _caml_young_limit, %eax
    jb L104
    leal 4(%eax), %eax
    movl $2301, -4(%eax)
    fldl 56(%ecx)
    fstpl (%eax)
    addl $12, %esp
    ret
L104: call _caml_call_gc
L105: jmp L103
L102: call _caml_ml_array_bound_error

The code is polluted by the possibility that a Z.t value might be a float, but the fact that this appears to be possible is only an artifact of Z.t's implementation as abstract type with C functions to operate on.

If Z.t was an ML type, then there would be a choice: either export its constructors, making it clear that it is not an alias for float, or not export its constructors, and compile modules M that depend on Z into generic code that will keep working if Z.t is ever changed to be an alias to float. This argument conflates what Z's programmer wants to show to M's programmer with what he wants to show to M's programmer's compiler, but fair is fair.

Unfortunately, there is no such alternative for custom types implemented as abstract type + C functions. The only way I see to provide this information is to provide too much information, in the form of fake, unsafe constructors that do not reflect the actual layout of the type.

Feature wish: a syntax to specify (only) that a custom type is never a float.

Alternately, in native compilation, the compiler could look through programmer-opaque interfaces for the actual implementation of abstract types. There is already no separate compilation to speak of because the compiler already looks for small functions to inline through interfaces that are opaque to the programmer, so there wouldn't be any loss here. Z's programmer would still have to write fake constructors in its module, but he wouldn't have to show them in the module's interface. He would only have to be careful not to pattern-match values of type Z.t in one module.
TagsNo tags attached.
Attached Files

- Relationships

-  Notes
(0006131)
ertai (developer)
2011-09-26 07:24

The alternative solution (making the native compiler, see through abstraction) seems more appealing to me.
(0006173)
gerd (reporter)
2011-10-23 14:40

Addition to the alternate solution: What about providing a special opaque type "non_float" in Pervasives (or maybe Obj), so module implementors can write:
type t = non_float.
(0006450)
garrigue (manager)
2011-12-21 14:39

Sorry for the slow answer.
If I am not confused, you can already tell the compiler that a type is not a float by writing:

   type t = private unit

Of course you may need some magic to have the system believe you.
And I do hope there are no bad side-effects.
(0006732)
lefessan (developer)
2012-01-19 14:13

I think there are two different problems here:
1/ when a type is manifest in the implementation, but becomes abstract in the interface;
2/ when a type is abstract from the beginning;

(1) could be solved by keeping some more information in the .cmx, about types, as it is already done for constant propagation and inlining. I think a patch would be welcome, just to get an idea of the complexity of doing that.

(2) could be solved using "private", but I am not completely sure ("private unit" might lead the compiler to believe the GC should not scan such values in the stack, which could be dangerous). Adding "non_float" is also dangerous, as the typer could unify different types equal to that one. Maybe an annotation on the type would be better, once such annotations are available.

- Issue History
Date Modified Username Field Change
2011-09-26 01:27 Pascal Cuoq New Issue
2011-09-26 07:24 ertai Note Added: 0006131
2011-10-23 14:40 gerd Note Added: 0006173
2011-12-21 14:39 garrigue Note Added: 0006450
2012-01-19 14:13 lefessan Note Added: 0006732
2012-01-19 14:13 lefessan Assigned To => lefessan
2012-01-19 14:13 lefessan Status new => confirmed
2012-01-25 23:12 lefessan Assigned To lefessan =>


Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker