-
Notifications
You must be signed in to change notification settings - Fork 36
Is exnref nullable? #90
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
Comments
If |
I'd almost say the opposite, that in those cases it doesn't need to be nullable: for parameters, the non-null value provides an initializing value for the parameter, and for returns it's just a value so there are no concerns about that. But if we expect to declare locals of type exnref without "let", or globals, or tables, then exnref must be nullable, or there will be no reasonable initialization value, unless we define an "empty" exception value to serve as that. |
Of course this will also work if I declare the value as Looking in the proposal I see there is no cast possible. I can assign it to a This will also ok for me because I use it only as boxing for a Conclusion: A nullable will give more options for the compiler writers. But I think the embedder must decide which impact this has. For a MVP a non nullable seems ok. |
It is nullable, otherwise we don't have any ways to initialize locals. And also, it is castable to I haven't thought about what to do on when |
If exnref <: anyref then upcasting just happens, as for all the other ref types, so that's not an issue. And it's fine for exnref to be non-nullable even if anyref is nullable, I don't understand what you mean by that not making sense - anyref can hold a strictly larger value set than exnref, and an upcast exnref -> anyref will be unproblematic. A downcast anyref -> exnref (with a cast operator, which we do not have, in the same way we do not have it for funcref or nullref) would need to check against null, if exnref were non-nullable, then against the type of the value. IMO, with nullable exnref, both Having thought about it slightly longer, I probably favor nullable exnref since exnref is a "fallback" type a la funcref; it needs to accomodate as many situations as possible. |
You're right, upcasting is not an issue. But we need it to be nullable for locals anyway.
Come to think of it, we may not need to trap after all. I don't see why throwing and rethrowing |
It's not a "problem", because we can always perform a null check in I also think that if |
I don't fully understand why throwing
I think this is true the other way around too :) |
IT would be cleaner if we didn't have nullability leak into exnref. On the other hand, if we want to avoid proposal dependencies, we could have both, and have this proposal start with nullable exnref, but later add non-null exnref, which would be a subtype. That would fit with the slight refactoring that introduces opt/non-opt ref types as part of the typed func ref proposal. @lars-t-hansen, in what sense is exnref a "fallback" type? The funcref type is a bit different, since its only use case is call_indirect, which involves a runtime type check anyway. That isn't true for exnref. |
It may be cleaner, but let's not forget that a major practical reason we switched to using reference types for exceptions in the first place is that the exception package needs to be able to escape the catch block. If exnref isn't nullable and there's no way other than a catch to initialize one, then that entire purpose is defeated. (In other words, even if we wait for non-nullable types and let bindings, it won't be useful for exceptions since there's not really a meaningful value for an exception package other than null or something thrown). I don't have strong feelings about allowing rethrow or |
If we allow null into exnref then trapping on rethrow is the only sensible choice. For example, in a typical engine, null wouldn't have any stack trace attached to it that rethrow may want to access and extend. Also, on the receiving side, there would be no way to distinguish null from an exception package that caught a thrown null, although these are quite different things. |
@dschuff
I'm not sure if I understand what 'null from an exception package' mean? @backes |
For that you can define an exception with no arguments.
What exnref value would you get when you catch null? Would it be distinguishable from null itself? Consider:
When control reaches (B), does that mean that (A) was never reached, or could it be the case that somebody threw null? (And in the latter case, is there a stack trace?) The semantics are muddied if you cannot distinguish these cases. But how could you distinguish them when you essentially made null a proper exception itself? |
FWIW, in general, there is no problem with initialisation of non-nullable exnrefs. It's trivial to define a dummy exception and use that as a null value where needed. The only problem is locals, which currently require an implicit default initialiser. That's why you'd want |
That makes sense.
I don't understand this part. Are there multiple
In this case, if we allow Just to be clear, I'm not against trapping on |
As @dschuff said, the whole purpose of introducing the current proposal was to allow But anyway, I would not like to make the EH proposal also dependent or blocked on the |
Simply because they are completely different things. One is an absent exception package, the other a present exception package that contains an empty exception value. The latter should e.g. be associated with a stack trace. A code pattern like the above would very likely be buggy code if null could be thrown. And you'd have to jump through additional hoops (maintaining an extra flag) to fix it. Most folks would likely be tempted to avoid the hassle and rather introduce the latent bug hoping that nobody else throws null. (This is the usual composition problem introduced by abusing the sentinel null for optional values on multiple levels, where you cannot distinguish an empty option from a non-empty option containing another empty option. It's the same conflation created by e.g. a dictionary whose lookup function returns null when a key is not present, but also allows null as a value. It's what e.g. led JS to introduce both null and undefined, which of course just kicks the can down the road, because undefined can also be used as a value.) |
Following the discussions in WebAssembly#90, it seems desirable and less error-prone to make `rethrow` and `br_on_exn` trap in case the value on top of the stack is of `nullref` type.
Not at all, that's easily doable. |
In #90 it was decided to move the event section between memory section and global section. This change is reflected in the next paragraph, but not in the introduction.
In #90 it was decided to move the event section between memory section and global section. This change is reflected in the next paragraph, but not in the introduction.
This was accidentally omitted.
Following the discussions in WebAssembly#90, it seems desirable and less error-prone to make `rethrow` and `br_on_exn` trap in case the value on top of the stack is of `nullref` type. Closes WebAssembly#90.
In WebAssembly#90 it was decided to move the event section between memory section and global section. This change is reflected in the next paragraph, but not in the introduction.
Following the discussions in WebAssembly#90, it seems desirable and less error-prone to make `rethrow` and `br_on_exn` trap in case the value on top of the stack is of `nullref` type. Closes WebAssembly#90.
In WebAssembly#90 it was decided to move the event section between memory section and global section. This change is reflected in the next paragraph, but not in the introduction.
AnyRef, FuncRef, and NullRef are all nullable: they have NullRef as a subtype and ref.null as a valid value. What about ExnRef? I would be inclined to think not, but I see the overview is quiet on this issue.
Clearly
throw
will never produce null but what happens withrethrow
andbr_on_exn
, if the exn on the stack is null?The text was updated successfully, but these errors were encountered: