- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
first make it real, then make it useful
Is there a sweet spot where something like this would be useful but not complicated? (Examples of complications I'm not real interested in: parameters are not each a completely distinct type, or you invent a language to communicate which expansions you want.)
class A { @annotation.expandDefaults def f(x: Int = 2, ys: List[String] = Nil, z: Option[Float] = None): String = "" + x + ys + z}
% scalap A class A extends java.lang.Object with scala.ScalaObject { def this() = { /* compiled code */ } @scala.annotation.expandDefaults def f(x : scala.Int, ys : scala.List[scala.Predef.String], z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(ys : scala.List[scala.Predef.String], z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int, z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int, ys : scala.List[scala.Predef.String]) : scala.Predef.String = { /* compiled code */ } def f(z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(ys : scala.List[scala.Predef.String]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int) : scala.Predef.String = { /* compiled code */ } def f() : scala.Predef.String = { /* compiled code */ } }
scala> (new A).f(List("abc"))res0: String = 2List(abc)None
scala> (new A).fres1: String = 2List()None
scala> (new A).f(Some(5.5))<console>:8: error: overloaded method value f with alternatives: (x: Int)String <and> (ys: List[String])String <and> (z: Option[Float])String cannot be applied to (Some[Double]) (new A).f(Some(5.5)) ^
scala> (new A).f(Some(5.5f))res3: String = 2List()Some(5.5)
class A { @annotation.expandDefaults def f(x: Int = 2, ys: List[String] = Nil, z: Option[Float] = None): String = "" + x + ys + z}
% scalap A class A extends java.lang.Object with scala.ScalaObject { def this() = { /* compiled code */ } @scala.annotation.expandDefaults def f(x : scala.Int, ys : scala.List[scala.Predef.String], z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(ys : scala.List[scala.Predef.String], z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int, z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int, ys : scala.List[scala.Predef.String]) : scala.Predef.String = { /* compiled code */ } def f(z : scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ } def f(ys : scala.List[scala.Predef.String]) : scala.Predef.String = { /* compiled code */ } def f(x : scala.Int) : scala.Predef.String = { /* compiled code */ } def f() : scala.Predef.String = { /* compiled code */ } }
scala> (new A).f(List("abc"))res0: String = 2List(abc)None
scala> (new A).fres1: String = 2List()None
scala> (new A).f(Some(5.5))<console>:8: error: overloaded method value f with alternatives: (x: Int)String <and> (ys: List[String])String <and> (z: Option[Float])String cannot be applied to (Some[Double]) (new A).f(Some(5.5)) ^
scala> (new A).f(Some(5.5f))res3: String = 2List()Some(5.5)










Re: first make it real, then make it useful
def f(x: Int = 5, y: Int = 3, z: Int = 1)
def f(Int,Int) // Is this x,y? x,z? y,z?
But you can provide all truncations:
def f(Int,Int,Int)
def f(Int,Int)
def f(Int)
def f()
--Rex
On Sun, Feb 12, 2012 at 6:28 PM, Paul Phillips <paulp [at] improving [dot] org> wrote:
Re: first make it real, then make it useful
On Mon, Feb 13, 2012 at 10:34 AM, Rex Kerr <ichoran [at] gmail [dot] com> wrote:> You can't do all combinations like you show because of multiple parameters of the same type:
I suppose that's why I said "Examples of complications I'm not real interested in: parameters are not each a completely distinct type."
Re: first make it real, then make it useful
Anyway, right now Scala allows
object O {
def f(i: Int = 7, s: String = "fish") = s*i
def f(a: Int) = a*a
}
where the latter is called when one argument is given. So the annotation would cause all sorts of collisions, potentially. There'd need to be some sort of crisp definition of how to avoid this.
But Scala doesn't allow
object O {
def f(s: String, i: Int = 5) = s*i
def f(b: Boolean, j: Int = 2) = List.fill(j)(b)
}
which is silly as no possible conflicts exist.
If the annotation, once fixed to do whatever collision-avoidance it does, allows for the latter case, then it sounds good to me; I've argued for fixing this before. If you are not allowed to expand defaults in more than one method, then I'm personally not terribly interested in it.
Also, you can have type parameter dependencies:
object P {
def f[A,B <: A](oa: Option[A] = None, ob: Option[B] = None) =
for (a <- oa; b <- ob) yield (a,b)
}
which would require some sort of rewriting when changed to single-parameter functions to keep the return type the same.
And then what happens when you inherit?
class Q { @expandDefaults def f(i: Int = 2, s: String = "wish") = s*i }
class R extends Q { override def f(a: Int, t: String = "dish") = t+a }
In particular, what happens to f()? Does it call f(Int) or f(Int,String) or f(String)? If it calls f(Int,String), it's going to use the non-overridden defaults, unless it magically gets recreated. Right now, I can call (new R).f() and get what I would expect from Liskov. How is that to be guaranteed with expansions?
--Rex
On Mon, Feb 13, 2012 at 2:32 PM, Paul Phillips <paulp [at] improving [dot] org> wrote:
Re: first make it real, then make it useful
Perhaps this trait will help you generalise your operation:
trait Point[[F[_]] {
def point[A](a: => A): F[A]
}
On 13/02/12 09:28, Paul Phillips wrote:
> Is there a sweet spot where something like this would be useful but
> not complicated? (Examples of complications I'm not real interested
> in: parameters are not each a completely distinct type, or you invent
> a language to communicate which expansions you want.)
>
> class A {
> @annotation.expandDefaults def f(x: Int = 2, ys: List[String] = Nil,
> z: Option[Float] = None): String = "" + x + ys + z
> }
>
> % scalap A
> class A extends java.lang.Object with scala.ScalaObject {
> def this() = { /* compiled code */ }
> @scala.annotation.expandDefaults
> def f(x : scala.Int, ys : scala.List[scala.Predef.String], z :
> scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ }
> def f(ys : scala.List[scala.Predef.String], z :
> scala.Option[scala.Float]) : scala.Predef.String = { /* compiled code */ }
> def f(x : scala.Int, z : scala.Option[scala.Float]) :
> scala.Predef.String = { /* compiled code */ }
> def f(x : scala.Int, ys : scala.List[scala.Predef.String]) :
> scala.Predef.String = { /* compiled code */ }
> def f(z : scala.Option[scala.Float]) : scala.Predef.String = { /*
> compiled code */ }
> def f(ys : scala.List[scala.Predef.String]) : scala.Predef.String =
> { /* compiled code */ }
> def f(x : scala.Int) : scala.Predef.String = { /* compiled code */ }
> def f() : scala.Predef.String = { /* compiled code */ }
> }
>
> scala> (new A).f(List("abc"))
> res0: String = 2List(abc)None
>
> scala> (new A).f
> res1: String = 2List()None
>
> scala> (new A).f(Some(5.5))
> :8: error: overloaded method value f with alternatives:
> (x: Int)String
> (ys: List[String])String
> (z: Option[Float])String
> cannot be applied to (Some[Double])
> (new A).f(Some(5.5))
> ^
>
> scala> (new A).f(Some(5.5f))
> res3: String = 2List()Some(5.5)
>
Re: first make it real, then make it useful
2012/2/13 Tony Morris <tonymorris [at] gmail [dot] com>
Re: first make it real, then make it useful
2012/2/13 Paul Phillips <paulp [at] improving [dot] org>
In which way do you find your own example complicated ? Seems to me it would work pretty well ...
Re: first make it real, then make it useful
scala> class A { def f(x: Int = 5, y: String = "abc") = () }defined class A
scala> def g(x: { def f(x: Int): Unit }) = ()g: (x: AnyRef{def f(x: Int): Unit})Unit
scala> g( new A )<console>:10: error: type mismatch; found : A required: AnyRef{def f(x: Int): Unit} g( new A ) ^
Re: Re: first make it real, then make it useful
Wouldn't it be better to enhance the type matching of structural types than to require the class author to know in advance her class is going to be used with a structural type?
Ittay
----
On 13 בפבר 2012 01:51, "Paul Phillips" <paulp [at] improving [dot] org> wrote:(Sent from my android)
RE: Re: first make it real, then make it useful
Chris
Date: Sun, 12 Feb 2012 15:51:57 -0800
Subject: [scala-debate] Re: first make it real, then make it useful
From: paulp [at] improving [dot] org
To: scala-debate [at] googlegroups [dot] com
By the way, what got me heading that way was this. Seems unfair to the default args.
scala> class A { def f(x: Int = 5, y: String = "abc") = () }defined class A
scala> def g(x: { def f(x: Int): Unit }) = ()g: (x: AnyRef{def f(x: Int): Unit})Unit
scala> g( new A )<console>:10: error: type mismatch; found : A required: AnyRef{def f(x: Int): Unit} g( new A ) ^