How to name a wildcard type?

872 views
Skip to first unread message

Piotr Kolaczkowski

unread,
Apr 22, 2014, 9:52:52 AM4/22/14
to scala...@googlegroups.com
I've got a method that returns an object of generic type with unknown generic argument:

def giveMeSth(): SomeGenericClass[_]

Is it possible to name the type argument of the object returned from such method, so it would be possible to refer to it in the following code by name?
 





Jason Zaugg

unread,
Apr 22, 2014, 10:07:00 AM4/22/14
to Piotr Kolaczkowski, scala-user
Can you share a concrete use case for this? From your description alone, I would say that what you are trying to do doesn't make much sense.

You can write the long-hand version of the code above: 

  def giveMeSth(): SomeGenericClass[X] forSome { type X }

But X is not in scope elsewhere.

You can also change SomeGenericClass to "publish" its type argument:

  trait SomeGenericClass[T] { type TT = T }
  val v: SomeGenericClass[_] = giveMeSth
  type X = v.TT

-jason

Message has been deleted

Piotr Kolaczkowski

unread,
Apr 22, 2014, 10:43:26 AM4/22/14
to scala...@googlegroups.com, Piotr Kolaczkowski
That was just a general question - I don't have any concrete code at hand.

Sometimes, when working with legacy Java API I get objects of type e.g. a List without a generic type parameter. Then working with such objects is much harder, because the type is not known and the compiler can't figure out e.g. two lists are of the same type, etc. I usually get around this by type casting, but sometimes I don't have a type in scope to cast them onto. 

e.g.:

val a = giveMeAList()   // ArrayList[_$1] 
val b = giveMeAnotherList()   // ArrayList[_$2] 
doSomethingWithLists(a, b)  // expects lists of the same type and doh - compile time error

I just wanted to know if there is a better solution than force casting them to Any or Nothing.

-- Piotr

Jerzy Muller

unread,
Apr 22, 2014, 6:54:39 PM4/22/14
to scala...@googlegroups.com
Underscore as a type parameter basically means „I don't care what type is there“, so naming it does not make sense.

Piotr Kolaczkowski

unread,
Apr 23, 2014, 3:15:56 AM4/23/14
to scala...@googlegroups.com

On Wednesday, April 23, 2014 12:54:39 AM UTC+2, Jerzy Muller wrote:
Underscore as a type parameter basically means „I don't care what type is there“, so naming it does not make sense.

This implication does not hold.
I personally may not care what type there is, but the compiler still does. Having no type name, I'm at the mercy of type inference. And we all know type inference is not perfect, and in some edge cases can't infer the right type and needs some help from the programmer.


Let me illustrate that with code:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Generic[T]
class GenericFactory[T] { 
  def create = new Generic[T] 
  def process(obj: Generic[T]) = println(s"got $obj") 
}
  
def gimmeFactory: GenericFactory[_] = new GenericFactory[Int]

val f = gimmeFactory 
val item = f.create   

f.process(item)   

// Exiting paste mode, now interpreting.

<console>:29: error: type mismatch;
 found   : Generic[_$1(in value res3)] where type _$1(in value res3)
 required: Generic[_$1(in value f)]
              f.process(item)   


Kevin Wright

unread,
Apr 23, 2014, 3:25:45 AM4/23/14
to Piotr Kolaczkowski, scala-user
It's hard to tell without more context, but it could be that you have a use-case for abstract type members:

class Generic { type T }
class GenericFactory { self =>
  type T
  def create = new Generic { type T = self.T }
  def process(obj: Generic) = println(s"got $obj") 
}
  
def gimmeFactory = new GenericFactory { type T = Int }

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Kevin Wright
mail: kevin....@scalatechnology.com
gtalk / msn : kev.lee...@gmail.com
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

Stephen Compall

unread,
Apr 26, 2014, 12:30:22 PM4/26/14
to Piotr Kolaczkowski, scala...@googlegroups.com
Yes.  Write a local generic function and pass the result of calling giveMeSth to it.

def blah(...): ... = {
  def withSth[A](sth: SomeGenericClass[A]): ... =
    42 // in this body you can use A to talk about the existential

  withSth(giveMeSth())
}

Whether this is sound -- and therefore works -- depends on the scope of the existential parameter, as denoted by where its equivalent forSome qualifier would appear.  In your example, where forSome is at the top level, and for any such existentially quantified type, this technique works.

-- 
Stephen Compall
"^aCollection allSatisfy: [:each|aCondition]": less is better

Jason Zaugg

unread,
Apr 26, 2014, 12:37:14 PM4/26/14
to Stephen Compall, Piotr Kolaczkowski, scala-user
Clever!

That reminds me, you can use a variable type pattern (lower case type argument to a type pattern) in a pattern match to name the existential.

scala> val x: Some[_] = Some("a")
x: Some[_] = Some(a)

scala> x match { case sa: Some[a] => var temp: a = sa.get; temp = sa.get; temp }
res3: Any = a 

-jason

Stephen Compall

unread,
Apr 26, 2014, 12:40:09 PM4/26/14
to Jason Zaugg, Piotr Kolaczkowski, scala-user
On Sat, 2014-04-26 at 18:37 +0200, Jason Zaugg wrote:
That reminds me, you can use a variable type pattern (lower case type argument to a type pattern) in a pattern match to name the existential.


scala> val x: Some[_] = Some("a")
x: Some[_] = Some(a)


scala> x match { case sa: Some[a] => var temp: a = sa.get; temp = sa.get; temp }
res3: Any = a

Whoa. When did that happen?

Jason Zaugg

unread,
Apr 26, 2014, 12:49:22 PM4/26/14
to Stephen Compall, Piotr Kolaczkowski, scala-user
On Sat, Apr 26, 2014 at 6:40 PM, Stephen Compall <stephen...@gmail.com> wrote:
On Sat, 2014-04-26 at 18:37 +0200, Jason Zaugg wrote:
scala> x match { case sa: Some[a] => var temp: a = sa.get; temp = sa.get; temp }
res3: Any = a

Whoa. When did that happen? 

Long enough ago for the corresponding specification to refer to lowercase `boolean` :)
  • A parameterized type pattern T[a1,...,an], where the ai  are type variable patterns or wildcards _. This type pattern matches all values which match T for some arbitrary instantiation of the type variables and wildcards. The bounds or alias type of these type variable are determined as described in (§8.3). 

  1. A type variable pattern is a simple identifier which starts with a lower case letter. However, the predefined primitive type aliases unit, boolean, byte, short, char, int, long, float, and double are not classified as type variable patterns. 

 -jason

Simeon Fitch

unread,
Apr 27, 2014, 11:39:38 AM4/27/14
to scala...@googlegroups.com, Jason Zaugg, Piotr Kolaczkowski

scala> x match { case sa: Some[a] => var temp: a = sa.get; temp = sa.get; temp }
res3: Any = a

Whoa. When did that happen?

Ditto! Thought you had to use TypeTag-s for that! <head explodes>

Jason Zaugg

unread,
Apr 27, 2014, 11:56:26 AM4/27/14
to Simeon Fitch, scala-user, Piotr Kolaczkowski
The `a` doesn't influence the conditional logic of the pattern match in any way. It just lets you bind a name to the (existential) type argument that can be used on the RHS of the case.

-jason

Reply all
Reply to author
Forward
0 new messages