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

Confused by Marshal type safety #5834

Closed
vicuna opened this issue Nov 19, 2012 · 1 comment
Closed

Confused by Marshal type safety #5834

vicuna opened this issue Nov 19, 2012 · 1 comment
Assignees

Comments

@vicuna
Copy link

vicuna commented Nov 19, 2012

Original bug ID: 5834
Reporter: warwick
Assigned to: @gasche
Status: closed (set by @xavierleroy on 2015-12-11T18:08:25Z)
Resolution: not a bug
Priority: low
Severity: feature
OS: Mac OS X
OS Version: 10.7.5
Version: 4.00.1
Category: ~DO NOT USE (was: OCaml general)

Bug description

This low-priority bug report shows more my misunderstanding of the Marshal.from_channel function rather than a problem with OCaml, but I wanted to register it anyway in case type safety could be added to the Marshal module as a feature in future.

If I (unwisely) send an extra parameter to a function that contains a command to un-marshall some data, and also fail to follow the instructions in the manual about explicitly setting the type of the data, then the compiler gives a warning ("Warning 20: this argument will not be used by the function."), but at run time the program crashes with a "Bus error: 10".

This happens when using both ocamlopt and ocamlc

If I explicitly specify the return type then the program gives the expected behaviour, and refuses to compile, giving: "Error: This function is applied to too many arguments".

Steps to reproduce

let loadData filename =
let channel = open_in_bin filename in
let data = Marshal.from_channel channel in
close_in channel;
data

let _ =
let _ = loadData "test.marshal" (* extra parameter: *) 1 in
()

@vicuna
Copy link
Author

vicuna commented Nov 19, 2012

Comment author: @gasche

The current behavior of Marshal with respect to typing is rather simple: functions of the Marshal module have a type of the form (foo -> 'a), where foo is the input type (string, in_channel, etc.). This means that their return type is fully polymorphic, just as the return type of (raise : exn -> 'a) for example.

You can do anything with a value of such a type and the type-checker can't stop you. The advice to add an explicit type annotation is precisely there to refine the static information of the program and allow for more static verification.

About warning 20: when an expression produced has a fully polymorphic type such as ('a), then in particular you can instantiate it to a function type of the form ('b -> 'c). But if it was produced without magic (Marshal or Obj) you know, statically, that this function will not use its argument. Indeed, to use its argument a function must evaluates to something of the form (fun foo -> ...), and therefore be type-checked as a function type (_ -> _) rather than a fully polymorphic type. Warning 20 is there to tell the programmer: "you're doing something weird by trying to pass an argument to something that I know isn't a regular function".

let rec loop arg = loop arg;;

val loop : 'a -> 'b =

loop () 1;;

Warning 20: this argument will not be used by the function.
Interrupted.

(raise Exit) 1;;

Warning 20: this argument will not be used by the function.
Exception: Pervasives.Exit.

Of course, in the context of Marshal, this warning isn't always appropriate because it may be the case that what you unmarshalled really is a function. It's only a way for the compiler to tell you it doesn't have any static knowledge about this function -- so annotating it with some type information would be a good idea, if only to provide better static information about the function return type.
To sum up, this warning is useful in other circumstances and doesn't hurt in this case. Besides it would be technically difficult/complicated to special-case the result of unmarshaling (that would require a non-local test) to disable the warning. I don't expect this behavior to change in a medium-term future.

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