Calling functions with more arguments then function needs should be ok.

80 views
Skip to first unread message

Miško Hevery

unread,
May 21, 2013, 1:50:38 PM5/21/13
to mi...@dartlang.org
var dst = function(a1, a2);

// Fails because we don't have enough arguments.
dst(1);

// Fails because we have too many arguments.
dst(1, 2, 3);

But I am going to argue that it should not. Having more then need is not an issue.

The use case.

As a framework developer I often need to call back into the app code. like this

appFn(a1, a2, a3, a4);

The args are sorted by the probability that the app will actually need them. I have to provide all since in some cases
all are relevant, but 95% case is that the app only needs a1.

So the App developer has to declare it like so

(a, b, c, d) => foo = a;
(a, b, c, d) => foo = a;

It is really an overkill. By saying that too many arguments is not an issue the developer could write this

(a) => foo = a;


We get a benefit if the runtime says we have insufficient number of args, but having too many is not an issue and only gets in the way. Can we change that?

Ladislav Thon

unread,
May 21, 2013, 2:24:24 PM5/21/13
to mi...@dartlang.org
Personally, I don't like your proposal. Too much of a JavaScript madness, if I may :-)

However, I've more than once wanted to omit some (or all) parameters of a callback, as the callback is just ignoring them. Your proposal is one way to do it, sure, but I think that the callback should opt in. Using some nonintrusive way... I don't know, something like (a)* => foo = a. Or whatever.

LT

Filipe Morgado

unread,
May 21, 2013, 2:24:31 PM5/21/13
to mi...@dartlang.org
I don't agree.

Calling a function with too many arguments is 99% of the time a programming error.
If these errors are not detected, our apps could gain side-effects difficult to debug.

There are safer ways to pass random parameters to random functions.

Bob Nystrom

unread,
May 21, 2013, 2:27:18 PM5/21/13
to General Dart Discussion

On Tue, May 21, 2013 at 10:50 AM, Miško Hevery <mi...@google.com> wrote:
We get a benefit if the runtime says we have insufficient number of args, but having too many is not an issue and only gets in the way. Can we change that?

The bug history for this is murky. Bug #1827 requests something different. In the comments, Sean asks to extend that to support what you're asking for:
I would take this a step further and say that (as in JavaScript) when a function (or method) is called with extra positional or named arguments, then instead of calling noSuchMethod on the function or method receiver), just ignore the extra arguments.  There of course should still be a static warning for this.
...
The big use case for this is registering callbacks which will be passed arguments which you don't care about, and thus do not want to include in the formal parameters of your callback.
That bug was then merged into #2706, which doesn't cover Sean's request.

Given that Dart has optional parameters, which are different from this request, discussions around it have been confusing. Probably the best path to get the language designers attention is to file a separate bug and clarify in the bug that it is not a duplicate of other issues related to optional parameters?

For what it's worth, I'm in favor of this. Callbacks and event handlers often don't care about the arguments they are passed, and it's annoying to have to do (_) or (_, __, ___) just to ignore them.

Cheers,

- bob

罗勇刚(Yonggang Luo)

unread,
May 21, 2013, 2:30:59 PM5/21/13
to Dart

i think we can use c style (a,...) to ignore it.

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
 
 

Filipe Morgado

unread,
May 21, 2013, 2:49:01 PM5/21/13
to mi...@dartlang.org, luoyo...@gmail.com


Terça-feira, 21 de Maio de 2013 19:30:59 UTC+1, Yonggang Luo escreveu:

i think we can use c style (a,...) to ignore it.

Now this, I like. The programmer's intent is explicit.

The original proposition would cause a lot confusion.

Cogman

unread,
May 21, 2013, 2:59:55 PM5/21/13
to mi...@dartlang.org
I don't really like this proposal at all.  Even adding the ellipsis operator doesn't really add a whole bunch to the language (After all, if you REALLY want to pass in more params, why not declare one of the params a list or array?) Is it really too hard to type something like

doSomething(needed, needed, [opt, opt, opt, opt]);

?


--

Vyacheslav Egorov

unread,
May 21, 2013, 3:41:07 PM5/21/13
to General Dart Discussion
Dart provides enough reflective capabilities to "loosen" your callbacks via them. Along this lines:

class GenericAdapter {
  final f;
  final argc;

  GenericAdapter(f)
    : f = f,
      argc = reflect(f).type.parameters.length;

  noSuchMethod(Invocation mirror) {
    Function.apply(f, mirror.positionalArguments.take(argc).toList());
  }
}

loosen(f) => new GenericAdapter(f);

void main() {
  final cb = loosen((x) => print(x));
  cb(1, 2); // => prints 1
  cb(1);  // => prints 2
  cb(); // This throws.
}

--
Vyacheslav Egorov

Alan Knight

unread,
May 21, 2013, 4:13:45 PM5/21/13
to General Dart Discussion
You can do it without either mirrors or noSuchMethod by using an "is" check and defining "call". There are some limitations, but on the assumption that we're only worried about positional arguments and that any checking we're doing on their types we can do supplementally to this, I think the following should work (suitably cleaned up if anyone was going to use this for real).

So, Dart won't let us ask how many arguments a function takes without using mirrors. But it has function types and can tell us if something matches them or not. So we define function types for a function of N arguments and then use an "is" check to see which one the function we're given matches.

Then we wrap it, similarly to what Vyacheslav did, but instead of using noSuchMethod, we provide N wrapper classes, each of which implements a call function with N arguments. This lets those objects emulate a function, so we can just invoke them.

typedef one(a);
typedef two(a, b);
typedef three(a, b, c);

register(f, expectedNumberOfParameters) {
  var wrapper;
  if (expectedNumberOfParameters == 1) wrapper = new Wrap1(f);
  if (expectedNumberOfParameters == 2) wrapper = new Wrap2(f);
  if (expectedNumberOfParameters == 3) wrapper = new Wrap3(f);
  return wrapper;
}


class Wrap1 {
  Wrap1(this.f);
  Function f;
  call(a) => f(a);
}

class Wrap2 {
  Function f;
  Wrap2(this.f);
  call(a, b) {
    if (f is one) return f(a);
    if (f is two) return f(a, b);
  }
}

class Wrap3 {
  Wrap3(this.f);
  Function f;
  call(a, b, c) {
    if (f is one) return f(a);
    if (f is two) return f(a, b);
    if (f is three) return f(a, b, c);
  }
}

foo1(a) => print("Takes one arg $a");
foo2(a, b) => print("Takes two args $a and $b");
foo3(a, b) => print("Takes three args $a, $b and $c");

main() {
  register(foo1, 1)("hello");
  register(foo1, 2)("hello", "world");
  register(foo1, 3)("hello", "and", "goodbye");
  var twoArgs = register(foo2, 3);
  twoArgs("need", "need", "ignored");
}

Bob Nystrom

unread,
May 21, 2013, 4:59:10 PM5/21/13
to General Dart Discussion
I think you can simplify that a lot. If the problem you're trying to solve is just, "I want to accept callback that takes a variable number of parameters" then just do:

typedef void OneArg(a);
typedef void TwoArgs(a, b);

/// Accepts callbacks that take either one or two parameters.
awesomeApi(Function callback) {
  if (callback is TwoArgs) {
    callback(1, 2);
  } else if (callback is OneArg) {
    callback(1);
  } else {
    throw 'too many!';
  }
}

main() {
  awesomeApi((a) => print('one $a'));
  awesomeApi((a, b) => print('two $a $b'));
  awesomeApi((a, b, c) => print('three $a $b $c'));
}

Seems to work fine. This also lets you do things JavaScript can't (as easily) do like, "If the callback takes one parameter then we pass X, if it takes two, we pass Y and Z."

Cheers!

- bob

Alan Knight

unread,
May 21, 2013, 5:23:46 PM5/21/13
to General Dart Discussion
Yes, that's true. I was thinking about the case of the framework potentially storing it somewhere or passing it around. So it's nice if when you're expecting a function that takes N arguments you just have to call register(f, N) and then you have something that looks like what you wanted, and you don't have to test when invoking it. But this distills it down to the essence.

Reply all
Reply to author
Forward
0 new messages