This is a great question! The answer is that this is an issue with your code, with our libraries and with the web standardization process in general. First of all, here's how you can fix your code so that it will run in chrome or safari:void set _color(Color3 color) {ctx.setStrokeColor(color.x, color.y, color.z, 1);ctx.setFillColor(color.x, color.y, color.z, 1);}You'll notice two key differences from your original code. First, these methods expect floats rather than ints. Second, they need to be called with 4 arguments including a non-optional alpha value.If all you care about is getting your code running, you can stop reading now...There are still some pretty nasty issues here:
- Your code will only work in webkit-based browsers. For example, if you run this in firefox you'll get an error that setStrokeColor is not a method. I'm not familiar with the history of this issue, but according to the latest version of the canvas draft spec, the mozilla folks are right - http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#colors-and-styles. This issue of differing versions of the web standards is a big deal for web developers. Our goals are to figure out how to shield you from as much of this as possible in dart; however, we are nowhere near achieving that goal yet. The fact that canvas wouldn't have existed if some engineers hadn't just built and shipped the thing for the first time without paying any attention to the standards bodies only complicates this question further.
- Even in webkit, this is a very hard method for us to define correctly in dart. If you go to the docs on MDN for CanvasRenderingContext2D, you'll see that this method has four overloads (two of which have one optional parameter). It isn't clear to us how best to represent such a method in dart - which has no method overloading. At the moment, the dart:dom library merges all four possible parameter signatures into one - using var and optional as needed to make things work. The problem is that this can easily lead to situations where neither dart's static nor runtime type checks will catch an error like the one you just made. This is very unfriendly to our developers. We've talked about a lot of other options - for example, using setStrokeColor0, setStrokeColor1, setStrokeColor2, and setStrokeColor3 to represent the four different signatures; however, this seems unfriendly to developers in a different way. We hope to come up with something really clever to resolve this dilemma in the dart:html library - but this particular problem hasn't been addressed yet and any good suggestions about how to proceed would be welcome.
I've been bitten by this one a few times already, and I would suggest that you don't try to emulate the DOM at all - in particular it seems bad to put the burden on the Canvas API to know of all the ways to represent a color. I'd suggest a single argument of type Color, which can have all sorts of named constructors to support hex, names, RGB, RGBA, etc.
Perhaps a feature request I submitted a little while back could help
with the overloading issue: http://code.google.com/p/dart/issues/detail?id=956.
This is what the api might look like with interleaved params:
ctx.setStrokeColor(colorString, a);
might be:
ctx.setStrokeColorNamed(colorString)withAlpha(a);
ctx.setStrokeColor(grayLevel, a);
might be:
ctx.setStrokeColorWithGrayLevel(grayLevel)alpha(a);
ctx.setStrokeColor(r,g,b,a);
might be:
ctx.setStrokeColorWithRed(r)green(g)blue(b)alpha(a);
ctx.setStrokeColor(c, m, y, k, a);
might be:
ctx.setStrokeColorWithCyan(cyan)magenta(m)yellow(y)darkness(k)alpha(a);
Anyway, since under this proposal each method would have a unique
name, overloading wouldn't be an issue. More readable API to boot in
my opinion.
- bob
Thinking out loud here...
I think you have three different set of arguments. What I mean is that
you'd probably want to overload this way:
setStrokeColor(String string, [num alpha = 1]) { ... }
setStrokeColor(num gray, [num alpha = 1]) { ... }
setStrokeColor(num r, num g, num b, [num a = 1]) { ... }
I don't even want to consider overloading based on types. But
overloading based on names of arguments is fine (it not really
overloading, the name of the method is just a little weirder). So
let's remove the types:
setStrokeColor(string, [alpha = 1]) { ... }
setStrokeColor(gray, [alpha = 1]) { ... }
setStrokeColor(r, g, b, [a = 1]) { ... }
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);
You'd have to write:
setStrokeColor(r: 1, g: 2, b: 3);
So perhaps another overload is needed:
/** This is for compatibility with JavaScript. If [arg3 !== null ||
arg4 !== null], forward to [setStrokeColor:r:g:b:], otherwise, if
[arg1 is String], forward to [setStrokeColor:string:], otherwise
forward to [setStrokeColor:gray:]. */
setStrokeColor(arg1, [arg2, arg3, arg4]) { ... }
Cheers,
Peter
+100
Required named arguments as part of function signature looks pretty
good for me.
This is a great question! The answer is that this is an issue with your code, with our libraries and with the web standardization process in general. First of all, here's how you can fix your code so that it will run in chrome or safari:void set _color(Color3 color) {ctx.setStrokeColor(color.x, color.y, color.z, 1);ctx.setFillColor(color.x, color.y, color.z, 1);}You'll notice two key differences from your original code. First, these methods expect floats rather than ints. Second, they need to be called with 4 arguments including a non-optional alpha value.
If all you care about is getting your code running, you can stop reading now...There are still some pretty nasty issues here:
- Your code will only work in webkit-based browsers. For example, if you run this in firefox you'll get an error that setStrokeColor is not a method. I'm not familiar with the history of this issue, but according to the latest version of the canvas draft spec, the mozilla folks are right - http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#colors-and-styles. This issue of differing versions of the web standards is a big deal for web developers. Our goals are to figure out how to shield you from as much of this as possible in dart; however, we are nowhere near achieving that goal yet. The fact that canvas wouldn't have existed if some engineers hadn't just built and shipped the thing for the first time without paying any attention to the standards bodies only complicates this question further.
I think you really have to step back and consider that the performance
hit could be OK for you in some cases, but not for others. A method
like this gets called a lot, and I don't think the object performance
would be acceptable to impose on people.
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);
On Thu, Jan 26, 2012 at 12:13 AM, Peter Ahé <a...@google.com> wrote:
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);I can't tell you how much I would love this. One nice thing about it is that it might also let us unify it with named constructors and not need to have those a special-case feature of constructors:new List(from: [1, 2, 3]);new List(length: 123);
On Thu, Jan 26, 2012 at 11:47 AM, Bob Nystrom <rnys...@google.com> wrote:
On Thu, Jan 26, 2012 at 12:13 AM, Peter Ahé <a...@google.com> wrote:
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);I can't tell you how much I would love this. One nice thing about it is that it might also let us unify it with named constructors and not need to have those a special-case feature of constructors:new List(from: [1, 2, 3]);new List(length: 123);I'm not a language guru by any means, but how is this different to overloading, which, it has been stated, Dart will not support?I really like this construct and if this means I get my overloaded constructors without having to name them, that makes me happy.
On Thu, Jan 26, 2012 at 11:47 AM, Bob Nystrom <rnys...@google.com> wrote:
On Thu, Jan 26, 2012 at 12:13 AM, Peter Ahé <a...@google.com> wrote:
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);I can't tell you how much I would love this. One nice thing about it is that it might also let us unify it with named constructors and not need to have those a special-case feature of constructors:new List(from: [1, 2, 3]);new List(length: 123);I'm not a language guru by any means, but how is this different to overloading, which, it has been stated, Dart will not support?
On Thu, Jan 26, 2012 at 11:47 AM, Bob Nystrom <rnys...@google.com> wrote:
On Thu, Jan 26, 2012 at 12:13 AM, Peter Ahé <a...@google.com> wrote:
I have previously argued that it would be horrible to make all
parameter names part of the API by default. However, I see no problem
when the method author explicitly do something to make parameter names
part of the API. We already have "optionally named arguments", perhaps
we should look at adding "required named arguments" (aka Smalltalk
keyword-sends). For example:
setStrokeColor(string:, [alpha = 1]) { ... }
setStrokeColor(gray:, [alpha = 1]) { ... }
setStrokeColor(r:, g:, b:, [a = 1]) { ... }
In this case, it would be an error to write:
setStrokeColor(1, 2, 3);I can't tell you how much I would love this. One nice thing about it is that it might also let us unify it with named constructors and not need to have those a special-case feature of constructors:new List(from: [1, 2, 3]);new List(length: 123);I'm not a language guru by any means, but how is this different to overloading, which, it has been stated, Dart will not support?I really like this construct and if this means I get my overloaded constructors without having to name them, that makes me happy.
It isn't overloading because required names are part of the method names (although it is pretty subtle).
What about:
var x = y ? foo : something_else;
x(a: bar);
x(b: bar);
The value of 'x' can be 'foo' or 'something_else' so the call can't be
known statically. Or would the version of 'foo' need to be specified
in the assignment?
Sure, especially in a ternary operator. Would you be able to specify
optional arguments in the same manner, even though they aren't
strictly part of the function name?