ocamljs
ocamljs copied to clipboard
Compiler crashes when setter/getter is called
The following code crashes the ocamljs compiler:
let f o = o#_get_x 1
it says:
Fatal error: exception Failure("bad method call")
while the following equivalent code compiles without crash:
let f o = let g = o#_get_x in g 1
It seems that the getter must not be applied directly to any argument, or ocamljs will die. Although it is not fatal since there's workaround, it might be better if a more informative message is provided.
Similarly, the following code, which misses the setter's argument, will crash:
let f o = o#_set_x
The error message is the same: Fatal error: exception Failure("bad method call")
Thank you for the bug report.
I think both these cases could be fixed: the first by applying the gotten value to any extra arguments, the second by generating a function for the partial application of the setter.
However, there is a larger problem here, which is that over/under application of Javascript methods does not work, since we don't know their arity (and in fact they may behave differently according to the arity of their arguments). This can't be caught in the type system.
I am somewhat reluctant to fix the getter/setter special cases (where we happen to know the arity), since it can't be fixed in general.
I think your original example had to do with a missed semicolon:
let f o = o#_set_x 1 o#_set_y 1
It would of course be nice to catch this kind of problem (accidental overapplication). I suggest that functions on native Javascript objects should always have their argument type-annotated to gain a little safety.
The only good alternative I can think of is to abandon normal OCaml method call syntax and use a special syntax for Javascript calls (like js_of_ocaml does). But I would like to be convinced that it is a very serious problem before taking that path.
Oh, also, it is difficult to give a good error message here because we are working with the lambda code, which no longer contains source locations. But it could probably be improved a little ("bad setter" / "bad getter" instead of "bad method call").
Thank you for your effort and immediate replies. Now I (partially) understood the problem.
I thought that overapplication to a setter should be treated as a type error. But it is impossible since it is detected in the translation phase (from lambda to js), not in the type-checking phase. Similar discussion applies to getters. correct?
(As I mentioned) I consider that this problem is not fatal. Improving the error message and explaining it in the FAQ is enough.
By the way, I'm curious about another workaround for getters, which treats
o#_get_x y z
as
let f=o#_get_x in f y z
(I do not suggest this as a solution, but just for curiosity!)
Yes, overapplication of a setter should be a type error, but we must know the type of the setter. If you write
class type foo =
object
method _set_x : int -> unit
end
let f (o : foo) = o#_set_x 1 2
then you get a type error. But if you leave off the annotation the compiler just propagates the constraint that _set_x has two argument to o. Now, it might be possible in ocamljs to add a type constraint 'a -> unit for all setters, but it seems like a hack, and would only work for setters. I think it is better to use annotations when working with native objects. (Actually, I find that it is very often necessary to use annotations whenever you use the object system.)
Your workaround for getters is what I meant by "applying the gotten value to any extra arguments". I think it would work fine, but since it can't work for other methods (because we don't know the arity) I think it might not be a good idea.