Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract static methods in Scala

I've read this relevant post, but there weren't many concrete answers (poor language design more or less): Why can't static methods be abstract in Java

I'm a bit of a newcomer to Scala, is this possible in it (maybe with traits or something)?

I tried having my base class extend a trait, but then child classes are required to implement the abstract static method as a member method, when I really want them to be required to be implemented in the companion object.

like image 566
Kevin Li Avatar asked Mar 21 '12 10:03

Kevin Li


2 Answers

There aren't static methods in Scala [*], so your question is moot.

However, you can get what you want by extending an object with a trait:

scala> trait A { def foo(): Int }
defined trait A

scala> object C extends A { def foo(): Int = 5 }
defined module C

scala> C.foo
res0: Int = 5

which probably does what you want. There isn't really any way to force something to be implemented in the companion object of a class. The companion object might not exist.

[*] Technically, there are, but this is more of an implementation detail than an overall philosophy. See Method in companion object compiled into static methods in scala?

like image 195
Matthew Farwell Avatar answered Oct 16 '22 22:10

Matthew Farwell


I'm not sure what you would like to do with an abstract static method in java, but the only potential use case I've seen described in the past (I wish I remembered by whom...) is calling a method directly on a generic type parameter.

i.e. if java allowed something like this...

// this is not valid java...
// let's pretend we can define a static method in an interface
interface Foo {
    static String Foo();
}

// a class that implements our interface
class FooImpl implements Foo {
    public static String Foo() {return "foo";}  
}

...we could use it on a generic parameter, to call Foo() directly on the type

static <T extends Foo> String Test() {
        return T.Foo(); // even if our hypothetical static interface
                        // was a valid thing, this would probably still fail
                        // due to type erasure      
}

This would make somewhat more sense in C# because:

  1. Reified generics mean the type does not get erased
  2. in C# operators are static methods and you can define your own operators

Basically this means in a "pretend C#" with static interfaces, you could use something corresponding to the above "pretend java" code to write a generic method that works on any type that defines a specific operator (e.g. everything that has a "+" operator).

Now, back to scala. How does scala address this scenario? In part it doesn't. Scala has no static methods: an object is a singleton (i.e. a class with only one instance) but still a class with normal, instance methods, i.e. on objects you're still calling methods on the only instance, not directly on the type (even operators are methods in scala).

So in scala we would write:

trait Foo { def Foo:String }
object FooImpl extends Foo { def Foo = "foo" }

def Test(f: Foo) = f.Foo

...and call our method with

scala> Test(FooImpl)
res0: String = foo
// note that FooImpl is still an instance (the only one) of FooImpl and not 
// the type itself

You can do some tricks with implicits to avoid passing the only instance as a parameter:

implicit def aFoo = FooImpl
def Test2(implicit f: Foo) = f.Foo

now this works:

scala> Test2
res1: String = foo

With more advanced tricks with implicits, scala also defines Numeric, that allows you to use operators on any numeric value, even though they don't implements a common interface out of the box.

like image 30
Paolo Falabella Avatar answered Oct 16 '22 22:10

Paolo Falabella