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

Syntax to specify that a custom type is never a float #5361

Closed
vicuna opened this issue Sep 25, 2011 · 6 comments
Closed

Syntax to specify that a custom type is never a float #5361

vicuna opened this issue Sep 25, 2011 · 6 comments

Comments

@vicuna
Copy link

vicuna commented Sep 25, 2011

Original bug ID: 5361
Reporter: Pascal Cuoq
Status: confirmed (set by @lefessan on 2012-01-19T13:13:30Z)
Resolution: open
Priority: normal
Severity: feature
Version: 3.12.1
Category: typing
Related to: #7485
Monitored by: @protz mehdi

Bug description

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

@vicuna
Copy link
Author

vicuna commented Sep 26, 2011

Comment author: ertai

The alternative solution (making the native compiler, see through abstraction) seems more appealing to me.

@vicuna
Copy link
Author

vicuna commented Oct 23, 2011

Comment author: gerd

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.

@vicuna
Copy link
Author

vicuna commented Dec 21, 2011

Comment author: @garrigue

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.

@vicuna
Copy link
Author

vicuna commented Jan 19, 2012

Comment author: @lefessan

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.

@vicuna
Copy link
Author

vicuna commented Dec 7, 2016

Comment author: @mshinwell

Removing the float array hack would presumably solve this problem.

@stedolan
Copy link
Contributor

With flat-float-array (#1294), the possibility that a type might be float no longer slows down array accesses, so this feature no longer seems necessary.

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