- From: Dave Longley <dlongley@digitalbazaar.com>
- Date: Sat, 27 Apr 2013 21:20:53 -0400
- To: Markus Lanthaler <markus.lanthaler@gmx.net>
- CC: Linked JSON <public-linked-json@w3.org>
- Message-ID: <517C7975.1060900@digitalbazaar.com>
On 04/27/2013 10:59 AM, Markus Lanthaler wrote: > On Thursday, April 25, 2013 5:54 PM, Dave Longley wrote: >>> I think you refer to the three that check the parameters. I believe >> that's >>> an error in your implementation. If you have a function like >>> >>> Future expand (JsonLdInput input, optional JsonLdOptions >> options); >>> and you call it without any parameters (expand()) it should throw an >>> TypeError instead of returning a Future. You have to keep in mind >> that these >>> things will most of the time be implemented in C++. You can't just >> omit a >>> parameter in that case. >> The problem is that it is unclear when that error should be thrown. >> When >> using Futures, it is expected that any errors will propagate via the >> Future's rejection API -- when an attempt is made to resolve the >> Future. >> It might be incorrect to throw TypeErrors prior to trying to resolve >> the Future. >> If the behavior is as you changed, then it will cause a lot of >> headache (code duplication) for APIs that are wrapped using Futures, as >> their errors will be passed via callback (eventually to the Future's >> rejected() callback), not immediately thrown. There may be other >> headaches like mixing try/catch with rejection callbacks during >> chaining. It's unclear how a C++ implementation for this would work -- >> it may always generate a Future that will be rejected in this case. > Good that you mention C++. If you define a function that has a > *non*-optional parameter and try to call it without passing any parameter in > a statically typed and compiled language your compiler will simply refuse to > compile your code. The reason is that you tried to call a non-existent > function. The compiler can't find any function with matches the signature > you used. When you call functions in JavaScript, you don't call *directly* into a corresponding C++ function, rather your script is JIT-compiled (or interpreted). This isn't different for a JavaScript function that has a native implementation. When you pass an incorrect number of parameters to such a function, this doesn't result in a compile time error, rather, a runtime error may be raised. There is a translation layer between the JS and the C++ and, typically, the parameters passed from JavaScript arrive at the C++ end in an array-like structure. This can be checked for length, etc. -- whatever you'd like. That's where you could decide to throw a TypeError -- which is a runtime error. In V8, implementing a simple JS function looks like this: static Handle<Value> foo(const Arguments& args) { ... } extern "C" void init(Handle<Object> target) { NODE_SET_METHOD(target, "foo", foo); } See: https://gist.github.com/lupomontero/2245562 > > So this has nothing to do with error propagation or wrapping existing APIs. > It is just a result of JavaScript being so lazy (or tolerant, depending on > how you look at it). WebIDL clearly differentiates between optional and > non-optional parameters. Obviously you can't omit a non-optional parameter. > > The thing where we seem to disagree is whether the function is called at all > or not. If I'm not completely misunderstanding you (and I doubt I am), you > are saying that the function will be called even if the signature used by > the caller doesn't correspond to the signature definition of the method. I'm > arguing that the function is not called at all and thus an error is raised > directly instead of being returned via the Future. It's a question of how functions that are "called in the Future" are *meant* to be understood. Does returning a Future from such a method *mean* that you use the Future to invoke the function later -- and thus, you haven't *actually* invoked anything yet so there should be no runtime errors? In other words, is the constructor for the Future an implementation detail that should be effectively abstracted away? Or should we be well-aware that there's a constructor that may be doing something more than just creating a way to invoke a function in the Future? Make sense? If the error is normally generated when you invoke the function, and, by using Futures we *mean* for a function to not actually be invoked until we try to resolve a Future, isn't it odd to throw any sort of exception related to its invocation before it is actually invoked? > > > > -- > Markus Lanthaler > @markuslanthaler > > -- Dave Longley CTO Digital Bazaar, Inc.
Received on Sunday, 28 April 2013 01:19:51 UTC