- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: Named Arguments - some thoughts
Wed, 2010-07-28, 12:16
On Tue, Jul 27, 2010 at 5:10 PM, Phil Bagwell wrote:
> Hi Martin,
>
> Just a couple of thoughts on Named Arguments.
>
>
>
> First I like them, this is not a critique. They are really neat
> to use in quite common circumstances.
>
>
>
> The fact that any function/method can be called in this way
> leads to the refactoring problem talked about at Scaladays. i.e. a
> programmer does not know if someone has written code that uses the argument
> names so cannot change them. This is very limiting and time consuming. The
> programmer has to think of good names for all arguments just in case someone
> wants to call their functions this way and then cannot change them.
>
>
>
> I would suggest that, by default, argument names are ‘private’. Programmers
> that write functions that would benefit from call by name should declare the
> names as ‘public’.
>
>
>
> Example syntax (not a recommendation)
>
> def foo (a:Int,b:Int)=a+b // private by default ie foo(a=1,b=2) gives
> compiler error
>
>
>
> def area (public height:Int=1,width:Int=1)=height*width // allows by name
> ie area(height=4) gives 4
>
>
>
> This arrangement means that on refactoring it is clear which arguments can
> be safely changed and which ones not. Also programmers can chose argument
> names carefully when making public while not worrying when just for internal
> use.
>
>
>
> Scaladoc needs to be changed to give the names of arguments for functions
> else you cannot find them in the first place.
>
Hi Phil,
I have thought about it. In principle an approach like the one you
outline is appealing. In practice every concrete proposal I have seen
is not so great. I think the issue might be better served through
convention. Assume named arguments are usable only if
- they are whole words that mean something, or
- they use camel case somewhere (i.e. have at least one upper case character.
That way, if you write
def copy(nbytes: Int) it would not be recommended that you use
nbytes as a named arg.
But if you write
def copy(numBytes: Int)
the implicit contract is that numBytes is well thought out and will not change.
Likewise if you write
def copy(length: Int)
length would be usable as named argument. The compiler would not need
to enforce that. It's just a convention serves as informal contract
between library writers and library users.
What do people think?
Wed, 2010-07-28, 12:57
#2
Re: Re: Named Arguments - some thoughts
Maybe `length` wasn't the best possible example, I can easily imagine that some future refactoring would have that class implement a common trait in which the argument has been named `size`.(which also raises some interesting questions about whether or not a subclass should be allowed to change argument names in an overridden method, but that's one for another discussion...)
My thoughts, in no particular order:
On 28 July 2010 12:16, martin odersky <martin.odersky@epfl.ch> wrote:
My thoughts, in no particular order:
- If convention is used, then it should be something that can be captured in an as-yet-unwritten static analysis tool for Scala. I can imagine using a spelling checker to determine if a name "means something", but wouldn't seriously consider doing so, the concept is just too ambiguous.
- I like Phil's suggestion, but I'm not 100% convinced that `public` is the correct keyword to use here, I just can't think of anything better right now :)
- Presumably, under such a scheme, case classes would get named arguments by default
On 28 July 2010 12:16, martin odersky <martin.odersky@epfl.ch> wrote:
On Tue, Jul 27, 2010 at 5:10 PM, Phil Bagwell <pbagwell@bluewin.ch> wrote:
> Hi Martin,
>
> Just a couple of thoughts on Named Arguments.
>
>
>
> First I like them, this is not a critique. They are really neat
> to use in quite common circumstances.
>
>
>
> The fact that any function/method can be called in this way
> leads to the refactoring problem talked about at Scaladays. i.e. a
> programmer does not know if someone has written code that uses the argument
> names so cannot change them. This is very limiting and time consuming. The
> programmer has to think of good names for all arguments just in case someone
> wants to call their functions this way and then cannot change them.
>
>
>
> I would suggest that, by default, argument names are ‘private’. Programmers
> that write functions that would benefit from call by name should declare the
> names as ‘public’.
>
>
>
> Example syntax (not a recommendation)
>
> def foo (a:Int,b:Int)=a+b // private by default ie foo(a=1,b=2) gives
> compiler error
>
>
>
> def area (public height:Int=1,width:Int=1)=height*width // allows by name
> ie area(height=4) gives 4
>
>
>
> This arrangement means that on refactoring it is clear which arguments can
> be safely changed and which ones not. Also programmers can chose argument
> names carefully when making public while not worrying when just for internal
> use.
>
>
>
> Scaladoc needs to be changed to give the names of arguments for functions
> else you cannot find them in the first place.
>
Hi Phil,
I have thought about it. In principle an approach like the one you
outline is appealing. In practice every concrete proposal I have seen
is not so great. I think the issue might be better served through
convention. Assume named arguments are usable only if
- they are whole words that mean something, or
- they use camel case somewhere (i.e. have at least one upper case character.
That way, if you write
def copy(nbytes: Int) it would not be recommended that you use
nbytes as a named arg.
But if you write
def copy(numBytes: Int)
the implicit contract is that numBytes is well thought out and will not change.
Likewise if you write
def copy(length: Int)
length would be usable as named argument. The compiler would not need
to enforce that. It's just a convention serves as informal contract
between library writers and library users.
What do people think?
Wed, 2010-07-28, 13:27
#3
Re: Re: Named Arguments - some thoughts
Willis Blackburn wrote:
> I do like the OP's proposal. On the other hand, maybe this isn't such a problem at all. Only public methods are affected (of course internal methods may also be called with named arguments, but the library maintainer will know where those situations exist), and even then only methods with multiple parameters (no one calls single-argument methods using named parameters), and developers, especially library developers, should be coming up with meaningful names for public-method parameters anyway. If the developer later wants to change the parameter names, then that's no different than any other API change. Even without named parameters, the developer cannot change the method name, the parameter types, or the order of the parameters without breaking code. I don't think that the need to avoid changing the parameter names is much of an additional burden.
+1. What if programmer changes class name, function name, field name,
any other name, argument count, etc? How changing of the argument name
is different from any other changes?
Refactoring tools have to be just as smart as they are with simple rename.
Another though that the decision whether to use named arguments or not
has to be taken at call site not at the definition site. I cant think of
a reason why library designer has to be against using public function
with named arguments. It's not his call. Don't want it to be used -
don't "publish" it.
Wed, 2010-07-28, 13:27
#4
Re: Re: Named Arguments - some thoughts
On Wed, Jul 28, 2010 at 6:16 AM, martin odersky <martin.odersky@epfl.ch> wrote:
Please no. Conventions will be broken and we're no better off. Also, it's only a name. Is there any great need for the API author to change a parameter name? Really? I can't change the method name either after having published my API. I think this is a non-issue, unless someone can provide a really good use-case.
Nils
What do people think?
Please no. Conventions will be broken and we're no better off. Also, it's only a name. Is there any great need for the API author to change a parameter name? Really? I can't change the method name either after having published my API. I think this is a non-issue, unless someone can provide a really good use-case.
Nils
Wed, 2010-07-28, 13:37
#5
Re: Re: Named Arguments - some thoughts
I think the fact that it's not possible to deprecate a parameter name is a problem.We could support something like
def m(@deprecatedName('a) b: Int) = ...
when changing the name from a to b. m(a = 1) would still compile but give a warning
On Wed, Jul 28, 2010 at 13:39, Kevin Wright <kev.lee.wright@gmail.com> wrote:
well, that we can't do because lots of existing code wouldn't compile.
Lukas
def m(@deprecatedName('a) b: Int) = ...
when changing the name from a to b. m(a = 1) would still compile but give a warning
On Wed, Jul 28, 2010 at 13:39, Kevin Wright <kev.lee.wright@gmail.com> wrote:
(which also raises some interesting questions about whether or not a subclass should be allowed to change argument names in an overridden method, but that's one for another discussion...)
well, that we can't do because lots of existing code wouldn't compile.
Lukas
My thoughts, in no particular order:
- If convention is used, then it should be something that can be captured in an as-yet-unwritten static analysis tool for Scala. I can imagine using a spelling checker to determine if a name "means something", but wouldn't seriously consider doing so, the concept is just too ambiguous.
- I like Phil's suggestion, but I'm not 100% convinced that `public` is the correct keyword to use here, I just can't think of anything better right now :)
- Presumably, under such a scheme, case classes would get named arguments by default
On 28 July 2010 12:16, martin odersky <martin.odersky@epfl.ch> wrote:
On Tue, Jul 27, 2010 at 5:10 PM, Phil Bagwell <pbagwell@bluewin.ch> wrote:
> Hi Martin,
>
> Just a couple of thoughts on Named Arguments.
>
>
>
> First I like them, this is not a critique. They are really neat
> to use in quite common circumstances.
>
>
>
> The fact that any function/method can be called in this way
> leads to the refactoring problem talked about at Scaladays. i.e. a
> programmer does not know if someone has written code that uses the argument
> names so cannot change them. This is very limiting and time consuming. The
> programmer has to think of good names for all arguments just in case someone
> wants to call their functions this way and then cannot change them.
>
>
>
> I would suggest that, by default, argument names are ‘private’. Programmers
> that write functions that would benefit from call by name should declare the
> names as ‘public’.
>
>
>
> Example syntax (not a recommendation)
>
> def foo (a:Int,b:Int)=a+b // private by default ie foo(a=1,b=2) gives
> compiler error
>
>
>
> def area (public height:Int=1,width:Int=1)=height*width // allows by name
> ie area(height=4) gives 4
>
>
>
> This arrangement means that on refactoring it is clear which arguments can
> be safely changed and which ones not. Also programmers can chose argument
> names carefully when making public while not worrying when just for internal
> use.
>
>
>
> Scaladoc needs to be changed to give the names of arguments for functions
> else you cannot find them in the first place.
>
Hi Phil,
I have thought about it. In principle an approach like the one you
outline is appealing. In practice every concrete proposal I have seen
is not so great. I think the issue might be better served through
convention. Assume named arguments are usable only if
- they are whole words that mean something, or
- they use camel case somewhere (i.e. have at least one upper case character.
That way, if you write
def copy(nbytes: Int) it would not be recommended that you use
nbytes as a named arg.
But if you write
def copy(numBytes: Int)
the implicit contract is that numBytes is well thought out and will not change.
Likewise if you write
def copy(length: Int)
length would be usable as named argument. The compiler would not need
to enforce that. It's just a convention serves as informal contract
between library writers and library users.
What do people think?
Wed, 2010-07-28, 13:37
#6
Re: Re: Named Arguments - some thoughts
On Wed, Jul 28, 2010 at 2:26 PM, Nils Kilden-Pedersen wrote:
> On Wed, Jul 28, 2010 at 6:16 AM, martin odersky
> wrote:
>>
>> What do people think?
>>
>
> Please no. Conventions will be broken and we're no better off. Also, it's
> only a name. Is there any great need for the API author to change a
> parameter name? Really? I can't change the method name either after having
> published my API. I think this is a non-issue, unless someone can provide a
> really good use-case.
>
I was arguing against having special syntax in the language to deal
with visibility of parameter names.
One possible point of view is that it's not a specific problem --
refactoring tools and deprecatedName warnings can take care of
renamings in a controlled way. That's fine with me.
The other point of view is that always finding definitive names of
parameters of public methods is too much of a burden to library
designers. My convention proposal was meant as a compromise to
accommodate these fears.
Cheers
Wed, 2010-07-28, 13:47
#7
Re: Re: Named Arguments - some thoughts
On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz wrote:
> I think the fact that it's not possible to deprecate a parameter name is a
> problem.
> We could support something like
> def m(@deprecatedName('a) b: Int) = ...
> when changing the name from a to b.
> m(a = 1) would still compile but give a warning
> On Wed, Jul 28, 2010 at 13:39, Kevin Wright
> wrote:
>>
Yes, adding a @deprecatedName annotation looks like a good idea.
Cheers
Wed, 2010-07-28, 13:47
#8
Re: Re: Named Arguments - some thoughts
On Wed, Jul 28, 2010 at 7:31 AM, martin odersky <martin.odersky@epfl.ch> wrote:
I agree. If anything, public should be default and one could make them private
As a library designer I agree, but it's no different than the burden of finding good class and method names. It's a burden we must bear.
I was arguing against having special syntax in the language to deal
with visibility of parameter names.
I agree. If anything, public should be default and one could make them private
The other point of view is that always finding definitive names of
parameters of public methods is too much of a burden to library
designers.
As a library designer I agree, but it's no different than the burden of finding good class and method names. It's a burden we must bear.
Wed, 2010-07-28, 13:57
#9
Re: Re: Named Arguments - some thoughts
I think this is a good suggestion, similar to a deprecated method forwarding to the new recommended one.
/Daniel
On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
/Daniel
On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
I think the fact that it's not possible to deprecate a parameter name is a problem. We could support something like
def m(@deprecatedName('a) b: Int) = ...
when changing the name from a to b. m(a = 1) would still compile but give a warning
Lukas
Wed, 2010-07-28, 14:07
#10
Re: Re: Named Arguments - some thoughts
On Wed, Jul 28, 2010 at 2:26 PM, martin odersky wrote:
> On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz wrote:
>> I think the fact that it's not possible to deprecate a parameter name is a
>> problem.
>> We could support something like
>> def m(@deprecatedName('a) b: Int) = ...
>> when changing the name from a to b.
>> m(a = 1) would still compile but give a warning
>> On Wed, Jul 28, 2010 at 13:39, Kevin Wright
>> wrote:
>>>
> Yes, adding a @deprecatedName annotation looks like a good idea.
And I thought overloading resolution was already tricky! I would need
to see a more detailed proposal to evaluate potential corner cases.
I'd be in favour of an annotation @VolatileParamName that could be
added to a parameter, method, class, or package object that could
trigger a warning if the param names were used by clients. It would be
nice parameterize this with a scope, as per private[x], but I guess
that would need additional syntax.
-jason
Tue, 2010-08-03, 21:07
#11
Re: Re: Named Arguments - some thoughts
I implemented @deprecatedName, see below. Overloading resolutionworks "as expected"; the only change is in wether a method is applicablewhen using named arguments (i.e. it's applicable also if the deprecated
name is used). Selection of the most specific does (as before) only dependon the parameter types.
Comments are welcome.
Lukas
scala> def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
scala> deprNam3(y = 10, b = 2)<console>:7: warning: the parameter name y has been deprecated. Use b instead. deprNam3(y = 10, b = 2) ^ <console>:7: error: parameter specified twice: b deprNam3(y = 10, b = 2) ^
scala> def f(x: Int)(@deprecatedName('x) y: Int) = x + y<console>:5: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def f(x: Int)(@deprecatedName('x) y: Int) = x + y ^
scala> object deprNam2 { | def f(@deprecatedName('s) x: String) = 1 | def f(s: Object) = 2 | | def g(@deprecatedName('x) s: Object) = 3 | def g(s: String) = 4 | }
scala> deprNam2.f(s = new Object) res1: Int = 2
scala> deprNam2.f(s = "dlfkj")<console>:7: warning: the parameter name s has been deprecated. Use x instead. deprNam2.f(s = "dlfkj") ^res2: Int = 1
scala> deprNam2.g(x = "dlkjf")<console>:7: warning: the parameter name x has been deprecated. Use s instead. deprNam2.g(x = "dlkjf") ^res3: Int = 3
scala> deprNam2.g(s = new Object)res4: Int = 3
On Wed, Jul 28, 2010 at 14:57, Jason Zaugg <jzaugg@gmail.com> wrote:
Comments are welcome.
Lukas
scala> def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
scala> deprNam3(y = 10, b = 2)<console>:7: warning: the parameter name y has been deprecated. Use b instead. deprNam3(y = 10, b = 2) ^ <console>:7: error: parameter specified twice: b deprNam3(y = 10, b = 2) ^
scala> def f(x: Int)(@deprecatedName('x) y: Int) = x + y<console>:5: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def f(x: Int)(@deprecatedName('x) y: Int) = x + y ^
scala> object deprNam2 { | def f(@deprecatedName('s) x: String) = 1 | def f(s: Object) = 2 | | def g(@deprecatedName('x) s: Object) = 3 | def g(s: String) = 4 | }
scala> deprNam2.f(s = new Object) res1: Int = 2
scala> deprNam2.f(s = "dlfkj")<console>:7: warning: the parameter name s has been deprecated. Use x instead. deprNam2.f(s = "dlfkj") ^res2: Int = 1
scala> deprNam2.g(x = "dlkjf")<console>:7: warning: the parameter name x has been deprecated. Use s instead. deprNam2.g(x = "dlkjf") ^res3: Int = 3
scala> deprNam2.g(s = new Object)res4: Int = 3
On Wed, Jul 28, 2010 at 14:57, Jason Zaugg <jzaugg@gmail.com> wrote:
On Wed, Jul 28, 2010 at 2:26 PM, martin odersky <martin.odersky@epfl.ch> wrote:
> On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
>> I think the fact that it's not possible to deprecate a parameter name is a
>> problem.
>> We could support something like
>> def m(@deprecatedName('a) b: Int) = ...
>> when changing the name from a to b.
>> m(a = 1) would still compile but give a warning
>> On Wed, Jul 28, 2010 at 13:39, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
> Yes, adding a @deprecatedName annotation looks like a good idea.
And I thought overloading resolution was already tricky! I would need
to see a more detailed proposal to evaluate potential corner cases.
I'd be in favour of an annotation @VolatileParamName that could be
added to a parameter, method, class, or package object that could
trigger a warning if the param names were used by clients. It would be
nice parameterize this with a scope, as per private[x], but I guess
that would need additional syntax.
-jason
Wed, 2010-08-04, 22:57
#12
Re: Re: Named Arguments - some thoughts
Hi Lukas,
I think @deprecatedName is a good thing and I think have a need for something similar but different.
Sometimes have a trait such as,
trait A {
def a: Any
}
For dramatization, assume the trait is in some 3rd-party library I don't have any control over. Now I want to mix this trait into a class where I'd like to write:
class B(a: Any) extends A {
val a = compute(a /* the parameter */)
}
The problem here is namespace pollution. Parameters occupy the same namespace as members.
I often work around this by using an underscore or some other form of disfiguration,
class B(_a: Any) extends A {
val a = compute(_a)
}
but that results in an uglier API for the caller.
Maybe there's a way out of this that I'm not thinking about (sure, I could pick a different name...) but I was thinking that an annotation such as,
class B(@publicName('a) _a: Any) extends A {
val a = compute(_a)
}
would be useful. What do you think?
I sometimes wish there was a qualifier to reference arguments to avoid such namespacing issues.
alex
On Tue, Aug 3, 2010 at 1:06 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
I think @deprecatedName is a good thing and I think have a need for something similar but different.
Sometimes have a trait such as,
trait A {
def a: Any
}
For dramatization, assume the trait is in some 3rd-party library I don't have any control over. Now I want to mix this trait into a class where I'd like to write:
class B(a: Any) extends A {
val a = compute(a /* the parameter */)
}
The problem here is namespace pollution. Parameters occupy the same namespace as members.
I often work around this by using an underscore or some other form of disfiguration,
class B(_a: Any) extends A {
val a = compute(_a)
}
but that results in an uglier API for the caller.
Maybe there's a way out of this that I'm not thinking about (sure, I could pick a different name...) but I was thinking that an annotation such as,
class B(@publicName('a) _a: Any) extends A {
val a = compute(_a)
}
would be useful. What do you think?
I sometimes wish there was a qualifier to reference arguments to avoid such namespacing issues.
alex
On Tue, Aug 3, 2010 at 1:06 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
I implemented @deprecatedName, see below. Overloading resolutionworks "as expected"; the only change is in wether a method is applicable when using named arguments (i.e. it's applicable also if the deprecated name is used). Selection of the most specific does (as before) only dependon the parameter types.
Comments are welcome.
Lukas
scala> def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
scala> deprNam3(y = 10, b = 2)<console>:7: warning: the parameter name y has been deprecated. Use b instead. deprNam3(y = 10, b = 2) ^ <console>:7: error: parameter specified twice: b deprNam3(y = 10, b = 2) ^
scala> def f(x: Int)(@deprecatedName('x) y: Int) = x + y<console>:5: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def f(x: Int)(@deprecatedName('x) y: Int) = x + y ^
scala> object deprNam2 { | def f(@deprecatedName('s) x: String) = 1 | def f(s: Object) = 2 | | def g(@deprecatedName('x) s: Object) = 3 | def g(s: String) = 4 | }
scala> deprNam2.f(s = new Object) res1: Int = 2
scala> deprNam2.f(s = "dlfkj")<console>:7: warning: the parameter name s has been deprecated. Use x instead. deprNam2.f(s = "dlfkj") ^res2: Int = 1
scala> deprNam2.g(x = "dlkjf")<console>:7: warning: the parameter name x has been deprecated. Use s instead. deprNam2.g(x = "dlkjf") ^res3: Int = 3
scala> deprNam2.g(s = new Object)res4: Int = 3
On Wed, Jul 28, 2010 at 14:57, Jason Zaugg <jzaugg@gmail.com> wrote:On Wed, Jul 28, 2010 at 2:26 PM, martin odersky <martin.odersky@epfl.ch> wrote:
> On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
>> I think the fact that it's not possible to deprecate a parameter name is a
>> problem.
>> We could support something like
>> def m(@deprecatedName('a) b: Int) = ...
>> when changing the name from a to b.
>> m(a = 1) would still compile but give a warning
>> On Wed, Jul 28, 2010 at 13:39, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
> Yes, adding a @deprecatedName annotation looks like a good idea.
And I thought overloading resolution was already tricky! I would need
to see a more detailed proposal to evaluate potential corner cases.
I'd be in favour of an annotation @VolatileParamName that could be
added to a parameter, method, class, or package object that could
trigger a warning if the param names were used by clients. It would be
nice parameterize this with a scope, as per private[x], but I guess
that would need additional syntax.
-jason
Thu, 2010-08-05, 08:37
#13
Re: Re: Named Arguments - some thoughts
In the example you give I think there are two cases. Either the "_a" of the subclass definesthe "a" of the trait, in which case you can do
class B(val a: Any) extends A
Otherwise, the parameter "_a" in the subclass is different from "a" in thetrait and I think it should therefore have a different name.
Lukas
On Wed, Aug 4, 2010 at 23:55, Alex Boisvert <alex.boisvert@gmail.com> wrote:
class B(val a: Any) extends A
Otherwise, the parameter "_a" in the subclass is different from "a" in thetrait and I think it should therefore have a different name.
Lukas
On Wed, Aug 4, 2010 at 23:55, Alex Boisvert <alex.boisvert@gmail.com> wrote:
Hi Lukas,
I think @deprecatedName is a good thing and I think have a need for something similar but different.
Sometimes have a trait such as,
trait A {
def a: Any
}
For dramatization, assume the trait is in some 3rd-party library I don't have any control over. Now I want to mix this trait into a class where I'd like to write:
class B(a: Any) extends A {
val a = compute(a /* the parameter */)
}
The problem here is namespace pollution. Parameters occupy the same namespace as members.
I often work around this by using an underscore or some other form of disfiguration,
class B(_a: Any) extends A {
val a = compute(_a)
}
but that results in an uglier API for the caller.
Maybe there's a way out of this that I'm not thinking about (sure, I could pick a different name...) but I was thinking that an annotation such as,
class B(@publicName('a) _a: Any) extends A {
val a = compute(_a)
}
would be useful. What do you think?
I sometimes wish there was a qualifier to reference arguments to avoid such namespacing issues.
alex
On Tue, Aug 3, 2010 at 1:06 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
I implemented @deprecatedName, see below. Overloading resolutionworks "as expected"; the only change is in wether a method is applicable when using named arguments (i.e. it's applicable also if the deprecated name is used). Selection of the most specific does (as before) only dependon the parameter types.
Comments are welcome.
Lukas
scala> def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
scala> deprNam3(y = 10, b = 2)<console>:7: warning: the parameter name y has been deprecated. Use b instead. deprNam3(y = 10, b = 2) ^ <console>:7: error: parameter specified twice: b deprNam3(y = 10, b = 2) ^
scala> def f(x: Int)(@deprecatedName('x) y: Int) = x + y<console>:5: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def f(x: Int)(@deprecatedName('x) y: Int) = x + y ^
scala> object deprNam2 { | def f(@deprecatedName('s) x: String) = 1 | def f(s: Object) = 2 | | def g(@deprecatedName('x) s: Object) = 3 | def g(s: String) = 4 | }
scala> deprNam2.f(s = new Object) res1: Int = 2
scala> deprNam2.f(s = "dlfkj")<console>:7: warning: the parameter name s has been deprecated. Use x instead. deprNam2.f(s = "dlfkj") ^res2: Int = 1
scala> deprNam2.g(x = "dlkjf")<console>:7: warning: the parameter name x has been deprecated. Use s instead. deprNam2.g(x = "dlkjf") ^res3: Int = 3
scala> deprNam2.g(s = new Object)res4: Int = 3
On Wed, Jul 28, 2010 at 14:57, Jason Zaugg <jzaugg@gmail.com> wrote:On Wed, Jul 28, 2010 at 2:26 PM, martin odersky <martin.odersky@epfl.ch> wrote:
> On Wed, Jul 28, 2010 at 2:22 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
>> I think the fact that it's not possible to deprecate a parameter name is a
>> problem.
>> We could support something like
>> def m(@deprecatedName('a) b: Int) = ...
>> when changing the name from a to b.
>> m(a = 1) would still compile but give a warning
>> On Wed, Jul 28, 2010 at 13:39, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
> Yes, adding a @deprecatedName annotation looks like a good idea.
And I thought overloading resolution was already tricky! I would need
to see a more detailed proposal to evaluate potential corner cases.
I'd be in favour of an annotation @VolatileParamName that could be
added to a parameter, method, class, or package object that could
trigger a warning if the param names were used by clients. It would be
nice parameterize this with a scope, as per private[x], but I guess
that would need additional syntax.
-jason
Thu, 2010-08-05, 17:57
#14
Re: Re: Named Arguments - some thoughts
On Thu, Aug 5, 2010 at 12:29 AM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
That's not an option in my case because I need to run compute(...) on "a" first:
val a = compute(a /* the parameter */)
Yes, the parameter is different from "a" in the trait and that's really the point. They live in the same namespace in the implementing class but to the client, it would be better if it still was named "a" as parameter to the constructor (same situation happens with methods, btw).
alex
In the example you give I think there are two cases. Either the "_a" of the subclass definesthe "a" of the trait, in which case you can do
class B(val a: Any) extends A
That's not an option in my case because I need to run compute(...) on "a" first:
val a = compute(a /* the parameter */)
Otherwise, the parameter "_a" in the subclass is different from "a" in thetrait and I think it should therefore have a different name.
Yes, the parameter is different from "a" in the trait and that's really the point. They live in the same namespace in the implementing class but to the client, it would be better if it still was named "a" as parameter to the constructor (same situation happens with methods, btw).
alex
Thu, 2010-08-05, 20:27
#15
Re: Re: Named Arguments - some thoughts
Yes, I understood that. The point I was trying to make is that since the "a" in thesubclass is a different thing than the one in the trait, it should also have a differentname to avoid confusion. Otherwise you'll get
val someB = new B(a = 10) someB.a == 10 // is false, which is not intuitive Lukas
On Thu, Aug 5, 2010 at 18:54, Alex Boisvert <alex.boisvert@gmail.com> wrote:
val someB = new B(a = 10) someB.a == 10 // is false, which is not intuitive Lukas
On Thu, Aug 5, 2010 at 18:54, Alex Boisvert <alex.boisvert@gmail.com> wrote:
On Thu, Aug 5, 2010 at 12:29 AM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
In the example you give I think there are two cases. Either the "_a" of the subclass definesthe "a" of the trait, in which case you can do
class B(val a: Any) extends A
That's not an option in my case because I need to run compute(...) on "a" first:
val a = compute(a /* the parameter */)
Otherwise, the parameter "_a" in the subclass is different from "a" in thetrait and I think it should therefore have a different name.
Yes, the parameter is different from "a" in the trait and that's really the point. They live in the same namespace in the implementing class but to the client, it would be better if it still was named "a" as parameter to the constructor (same situation happens with methods, btw).
alex
Fri, 2010-08-06, 04:51
#16
Re: Re: Named Arguments - some thoughts
In my case, compute(a) returns a normalized representation of "a" which is semantically equivalent, so:
val someB = new B(a = 10) someB.a == 10 // would actually return true
There are also other cases where someB.a would not be visible to the client, maybe "a" is protected or private[package]. And remember, it can also happen with methods not just constructors.
alex
On Thu, Aug 5, 2010 at 12:16 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
val someB = new B(a = 10) someB.a == 10 // would actually return true
There are also other cases where someB.a would not be visible to the client, maybe "a" is protected or private[package]. And remember, it can also happen with methods not just constructors.
alex
On Thu, Aug 5, 2010 at 12:16 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
Yes, I understood that. The point I was trying to make is that since the "a" in thesubclass is a different thing than the one in the trait, it should also have a differentname to avoid confusion. Otherwise you'll get
val someB = new B(a = 10) someB.a == 10 // is false, which is not intuitive Lukas
On Thu, Aug 5, 2010 at 18:54, Alex Boisvert <alex.boisvert@gmail.com> wrote:
On Thu, Aug 5, 2010 at 12:29 AM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
In the example you give I think there are two cases. Either the "_a" of the subclass definesthe "a" of the trait, in which case you can do
class B(val a: Any) extends A
That's not an option in my case because I need to run compute(...) on "a" first:
val a = compute(a /* the parameter */)
Otherwise, the parameter "_a" in the subclass is different from "a" in thetrait and I think it should therefore have a different name.
Yes, the parameter is different from "a" in the trait and that's really the point. They live in the same namespace in the implementing class but to the client, it would be better if it still was named "a" as parameter to the constructor (same situation happens with methods, btw).
alex
I don't think that the convention solution will avoid the problems that the OP mentioned. Ideally the author of some library and every user of that library will be aware of and will support the conventions, but that's not a likely situation. Some people will be ignorant of the conventions, and others will simply not support them because they are inconvenient. (For example, if I have a case class called Point with members x and y, does the convention mean that I should not call copy with the named parameter y?)
I do like the OP's proposal. On the other hand, maybe this isn't such a problem at all. Only public methods are affected (of course internal methods may also be called with named arguments, but the library maintainer will know where those situations exist), and even then only methods with multiple parameters (no one calls single-argument methods using named parameters), and developers, especially library developers, should be coming up with meaningful names for public-method parameters anyway. If the developer later wants to change the parameter names, then that's no different than any other API change. Even without named parameters, the developer cannot change the method name, the parameter types, or the order of the parameters without breaking code. I don't think that the need to avoid changing the parameter names is much of an additional burden.
W
On Jul 28, 2010, at 7:16 AM, martin odersky wrote:
> On Tue, Jul 27, 2010 at 5:10 PM, Phil Bagwell wrote:
>> Hi Martin,
>>
>> Just a couple of thoughts on Named Arguments.
>>
>>
>>
>> First I like them, this is not a critique. They are really neat
>> to use in quite common circumstances.
>>
>>
>>
>> The fact that any function/method can be called in this way
>> leads to the refactoring problem talked about at Scaladays. i.e. a
>> programmer does not know if someone has written code that uses the argument
>> names so cannot change them. This is very limiting and time consuming. The
>> programmer has to think of good names for all arguments just in case someone
>> wants to call their functions this way and then cannot change them.
>>
>>
>>
>> I would suggest that, by default, argument names are ‘private’. Programmers
>> that write functions that would benefit from call by name should declare the
>> names as ‘public’.
>>
>>
>>
>> Example syntax (not a recommendation)
>>
>> def foo (a:Int,b:Int)=a+b // private by default ie foo(a=1,b=2) gives
>> compiler error
>>
>>
>>
>> def area (public height:Int=1,width:Int=1)=height*width // allows by name
>> ie area(height=4) gives 4
>>
>>
>>
>> This arrangement means that on refactoring it is clear which arguments can
>> be safely changed and which ones not. Also programmers can chose argument
>> names carefully when making public while not worrying when just for internal
>> use.
>>
>>
>>
>> Scaladoc needs to be changed to give the names of arguments for functions
>> else you cannot find them in the first place.
>>
> Hi Phil,
>
> I have thought about it. In principle an approach like the one you
> outline is appealing. In practice every concrete proposal I have seen
> is not so great. I think the issue might be better served through
> convention. Assume named arguments are usable only if
>
> - they are whole words that mean something, or
> - they use camel case somewhere (i.e. have at least one upper case character.
>
> That way, if you write
>
> def copy(nbytes: Int) it would not be recommended that you use
> nbytes as a named arg.
>
> But if you write
>
> def copy(numBytes: Int)
>
> the implicit contract is that numBytes is well thought out and will not change.
> Likewise if you write
>
> def copy(length: Int)
>
> length would be usable as named argument. The compiler would not need
> to enforce that. It's just a convention serves as informal contract
> between library writers and library users.
>
> What do people think?
>