W3C home > Mailing lists > Public > public-linked-json@w3.org > April 2013

RE: JSON-LD API w/DOM Futures implemented

From: Markus Lanthaler <markus.lanthaler@gmx.net>
Date: Sun, 28 Apr 2013 11:19:17 +0200
To: "'Linked JSON'" <public-linked-json@w3.org>
Message-ID: <00ac01ce43f1$7678ca50$636a5ef0$@lanthaler@gmx.net>
On Sunday, April 28, 2013 3:21 AM, Dave Longley wrote:
> On 04/27/2013 10:59 AM, Markus Lanthaler wrote:
> > 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.

But I wasn't talking about JavaScript at all. I was talking about C++. About
statically typed and compiled languages. WebIDL is not JavaScriptIDL. It is
a generic interface description language. It has a ECMAScript binding but
that doesn't change the fact that it is intended to be generic.


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

Of course not. How could it if you "compile" at runtime?


> 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

That doesn't matter in this instance. But just to present another
perspective on this. This is how Mozilla does it:

https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings#C.2B.2B_ref
lections_of_WebIDL_operations_(methods)


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

The methods we are talking about are not called in the Future they are
called instantaneously. It is the return value that is returned in the
Future.


> 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?

You have invoked the function. It returns a Future. You don't know when the
Future will be resolved. The point is that all the complex operations to
resolve the Future are done asynchronously. That doesn't change the fact
that the method call itself is synchronous.


> 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?

I don't understand this paragraph. The Future constructor doesn't create "a
way to invoke a function in the future". It creates a placeholder object for
a return value that is not ready yet to be returned. At some point in the
future that return value will be available and you can use it. You can
register a callback to be notified when that happens.


> 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?

No, because we (well, at least I) don't mean "for a function to not actually
be invoked until we try to resolve a Future". We don't try to resolve a
Future. The method passed to the Future constructor resolves the Future. We
just register a callback to be notified when that happens.

I think you are interpreting too much into Futures. Let's go back to the
original definition (and make the callback optional):

  void expand (JsonLdInput input, optional JsonLdCallback callback);

What should happen if I call this method without any parameters, expand()?
It should throw an error, right? I have to pass an input.

So let's now assume we change the return value from void to CallbackRegistry
and remove the callback parameter (it was optional anyway), nothing else
will be changed, the callback is just never called.

  CallbackRegistry expand (JsonLdInput input);

What should happen if I call this method without any parameters? I think we
agree it should still throw an error, right?

What if we now say that instead of calling the callback that has been passed
directly in the first example we allow the caller to register the callback
using the CallbackRegistry?

  var cbRegistry = expand (JsonLdInput input);
  cb.registerCallback(myCallback);

It would still throw an error if I call expand(), right?

Finally, we decide to do some refactoring and rename some things. Our
definition would end up looking as follows:

  Future expand (JsonLdInput input);

I would also need to change my code slightly because the "registerCallback"
method was renamed to "done":

  var future = expand (JsonLdInput input);
  future.done(myCallback);

Would calling expand() without any parameters still throw an error? Yes, why
not? Do we have Futures now, yes.

I hope this clarifies how I see things. I would love to see why you think
that the last code snipped shouldn't throw an error.


Cheers,
Markus


--
Markus Lanthaler
@markuslanthaler
Received on Sunday, 28 April 2013 09:19:52 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 16:18:37 UTC