More Variable Argument Constructor Confusion

23 views
Skip to first unread message

Seyed H. HAERI (Hossein)

unread,
May 31, 2012, 11:13:58 AM5/31/12
to scala-user
Dear all,

What is my chance to get something of type (X, (Y, Z)*) implicitly
converted to X(X, (Y, Z)*)? The companion object of my class X does
already provide a (X, (Y, Z)*) constructor which works fine. (Thanks
to the folks who helped me on that earlier on in the list.) My guess
was that placing the following in my package object would do:

implicit def tups2X(pair: (X, (Y, Z)*)) = X(pair._1, pair._2)

However, the compiler emits: "no * parameter type allowed here". If I
change the above line to

implicit def tups2X(pair: (X, (Y, Z)*)) = X(pair._1, pair._2: _*)

it will get even worse because I then get another error stating "')'
expected but '_' found" and pointing to my trailing addition above.
Any idea?

TIA,
--Hossein

--------------------------------------------------------------------------------------------------------------

Seyed H. HAERI (Hossein)

Research Assistant
Institute for Software Systems (STS)
Technical University of Hamburg (TUHH)
Hamburg, Germany

ACCU - Professionalism in programming - http://www.accu.org/
--------------------------------------------------------------------------------------------------------------

Erik Osheim

unread,
May 31, 2012, 11:19:32 AM5/31/12
to Seyed H. HAERI (Hossein), scala-user
On Thu, May 31, 2012 at 05:13:58PM +0200, Seyed H. HAERI (Hossein) wrote:
> implicit def tups2X(pair: (X, (Y, Z)*)) = X(pair._1, pair._2)

A* is not a type, but rather syntax for variable argument lists. So I
think you can only use the "*" after an argument type, not inside
inside of a tuple or other type.

Maybe you want something like this?

implicit def tupls2x(pair:(X, Seq[(Y, Z)])) = ...

Hope this helps.

-- Erik

Seyed H. HAERI (Hossein)

unread,
May 31, 2012, 11:39:44 AM5/31/12
to scala-user
Hi Erik,

> Maybe you want something like this?
>
>  implicit def tupls2x(pair:(X, Seq[(Y, Z)])) = ...

No that doesn't. I tried

implicit def tupls2x(pair:(X, Seq[(Y, Z)])) = X(pair._1, pair._2.toMap)

and couldn't still get things of type (X, (Y, Z)) converted to X
because (Y, Z) is not a Seq[(Y, Z)]. I even tried making my X.apply(X,
(Y, Z)*) implicit, but, that didn't work either. Anything now?

missingfaktor

unread,
May 31, 2012, 12:28:21 PM5/31/12
to Seyed H. HAERI (Hossein), scala-user
(X, (Y, Z)*) is not a valid type. (You seem to be misunderstanding tuples, varargs, and parameter lists.)

You can (and should) change your design as Erik suggested.

case class X(x: X, yzs: Seq[(Y, Z)])

implicit def tuple2x(pair: (X, Seq[(Y, Z)]) = X(pair._1, pair._2)


If you still want the varargs support for X's construction, write a factory method for that.

object X {
  def apply(x: X, yzs: (Y, Z)*) = X(x, yzs.toSeq)
}

This way you can have your cake and eat it too.
--
Cheers,

Seyed H. HAERI (Hossein)

unread,
May 31, 2012, 12:47:00 PM5/31/12
to scala-user
Hi Rahul,

> (X, (Y, Z)*) is not a valid type. (You seem to be misunderstanding tuples, varargs, and parameter lists.)

I got his point on this. But, that doesn't solve my problem. See below.

> You can (and should) change your design as Erik suggested.
>
> case class X(x: X, yzs: Seq[(Y, Z)])
> implicit def tuple2x(pair: (X, Seq[(Y, Z)]) = X(pair._1, pair._2)
>
> If you still want the varargs support for X's construction, write a factory
> method for that.
>
> object X {
>   def apply(x: X, yzs: (Y, Z)*) = X(x, yzs.toSeq)
> }
>
> This way you can have your cake and eat it too.

No, that's wrong. I have a function f(T, X): T that I would like to
have the option of calling it like f(t, (x, y1 -> z1, y2 -> z2)). This
call fits perfectly in the domain I'm programming in. But, changing
f's signature to accommodate a call like f(t, x, y1 -> z1, y2 -> z2)
doesn't. Your current design doesn't facilitate my desired function
call. Regardless of my trials so far, is there any way to achieve that
at all?

Josh Suereth

unread,
May 31, 2012, 1:12:59 PM5/31/12
to Seyed H. HAERI (Hossein), scala-user
You're in the realm of overloading, not implicits.   Varargs *only* exists in function argument land.   You can't 'keep' that and move into type-conversion land.

missingfaktor

unread,
May 31, 2012, 1:13:33 PM5/31/12
to Seyed H. HAERI (Hossein), scala-user
Does this following REPL session help at all?

scala> class Y; class Z
defined class Y
defined class Z

scala> case class X(x: X, yzs: (Y, Z)*)
defined class X

scala> def f(x: X, y: (Y, Z)*) = 2
f: (x: X, y: (Y, Z)*)Int

scala> val x = X(null, (new Y, new Z), (new Y, new Z))
x: X = X(null,WrappedArray((Y@17f0649,Z@75c229), (Y@11e4232,Z@18be33e)))

scala> f(x.x, x.yzs : _*)
res58: Int = 2

If not, I am not sure I understand what your question is.
--
Cheers,

Som Snytt

unread,
May 31, 2012, 2:56:49 PM5/31/12
to Seyed H. HAERI (Hossein), scala-user
This works, sort of.  The compiler is willing to see the arg list to f as a tuple, so if you provide the implicit, it will use it.  Maybe write some code in your build to generate as many tuple conversions as your use case requires.  As noted previously, the star notation doesn't work because the conversion is from a provided type to a (singular) expected type, and there is no "untupling" when asking if an implicit applies.

class X {
  def m() = ???
}

object Test {
  //implicit def tupX(x: X, ps: Pair[Int,Int]*): X = ???
  implicit def tup3X(t: Tuple3[X, Pair[Int,Int], Pair[Int,Int]]): X = ???
  def f(x: X) = ???
  def main(args: Array[String]) {
    f(new X, 1 -> 2, 7 -> 9)
    (new X, 1 -> 2, 7 -> 9).m()

Seyed H. HAERI (Hossein)

unread,
May 31, 2012, 6:05:40 PM5/31/12
to scala-user
OK guys. I guess that's it; I can't do that... :( Thank you everyone anyway.

On 31 May 2012 21:17, Tom Switzer <thomas....@gmail.com> wrote:
>
>
> On Thu, May 31, 2012 at 12:47 PM, Seyed H. HAERI (Hossein)
> <hossei...@gmail.com> wrote:
>>
>> Hi Rahul,
>>
>> > (X, (Y, Z)*) is not a valid type. (You seem to be misunderstanding
>> > tuples, varargs, and parameter lists.)
>>
>> I got his point on this. But, that doesn't solve my problem. See below.
>>
>> > You can (and should) change your design as Erik suggested.
>> >
>> > case class X(x: X, yzs: Seq[(Y, Z)])
>> > implicit def tuple2x(pair: (X, Seq[(Y, Z)]) = X(pair._1, pair._2)
>> >
>> > If you still want the varargs support for X's construction, write a
>> > factory
>> > method for that.
>> >
>> > object X {
>> >   def apply(x: X, yzs: (Y, Z)*) = X(x, yzs.toSeq)
>> > }
>> >
>> > This way you can have your cake and eat it too.
>>
>> No, that's wrong. I have a function f(T, X): T that I would like to
>> have the option of calling it like f(t, (x, y1 -> z1, y2 -> z2)). This
>> call fits perfectly in the domain I'm programming in. But, changing
>> f's signature to accommodate a call like f(t, x, y1 -> z1, y2 -> z2)
>> doesn't. Your current design doesn't facilitate my desired function
>> call. Regardless of my trials so far, is there any way to achieve that
>> at all?
>
>
> Well, no, because the way you are calling f is with 2 arguments. You want
> the 2nd argument to have variable number of elements, but are unwilling to
> wrap it in a Seq or List or something and you will only accept bare
> parenthesis. Scala will see the parenthesized "list" and treat it as a
> n-tuple (n is the number of elements in the 2nd argument). That's because
> what you are writing is a short-hand syntax for a tuple. You can't
> arbitrarily nest variable arguments like you want to do. So, no, you can't
> do what you want.
>
> However, as Som Snytt pointed out, you may be able to make use of the tuple
> syntax you are using. You can either override f for Tuple2 through to
> Tuple22, or you can use some implicit conversions to convert (A, A, ..., A)
> to a Seq[A].
>
>>
>>
>> TIA,
>> --Hossein
>>
>>
>> --------------------------------------------------------------------------------------------------------------
>>
>> Seyed H. HAERI (Hossein)
>>
>> Research Assistant
>> Institute for Software Systems (STS)
>> Technical University of Hamburg (TUHH)
>> Hamburg, Germany
>>
>> ACCU - Professionalism in programming - http://www.accu.org/
>>
>> --------------------------------------------------------------------------------------------------------------
>
>



--
Reply all
Reply to author
Forward
0 new messages