0

How can I pass a variable list of parameters and types to a function? I.e. the depicted approach which is using pattern matching seems a bit clumsy. In an trait the function foo is defined. However in concrete implementations a different subtype (with additional fields should be used). Is there a cleaner approach than using pattern matching?

def foo[T <: MyBaseConfiguration](config: T) = {
  println("do smething")
  println(config.configValue)
}

override def foo[T <: MyBaseConfiguration](config: T) = {
  config match {
    case c: MyOtherConfiguration => {
      println("do smething else")
      println(c.configValue)
      println(c.otherValue)

    }
  }
}

trait MyBaseConfiguration {
  def configValue: String
}

class MyOtherConfiguration extends MyBaseConfiguration {
  val otherValue = 1234

  override def configValue = "abcd"
}

edit

Basicylly, I just want to say * there is a function f with a defined return value TReturn but be agnostic to input parameters. Still, I need to be able to use / access them during the execution of f.

9
  • 1
    The simple answer is that def foo(x: Any*): TReturn will allow you to "pass a variable list of parameters and types to a function" but I suspect that is not what you want. I think you need to explain how you want to use this function that you are describing. Commented Dec 19, 2018 at 13:38
  • Indeed, inside the function I want to be able to refer to i.e. the configuration values of otherValue and configValue and still keep type safety. Commented Dec 19, 2018 at 13:39
  • 1
    You could keep what Tim suggested and then simply do a match / case for the type. Once it's matched, you can access the config values. For example in my project we use specific type of configs (that extend a general config). And then we do this when we want to use the specific type of config: val felixConf = config.asInstanceOf[FelixConfig] . (Although case / match probably would be better, especially if you don't have a specific type you want to extend from) Commented Dec 19, 2018 at 13:45
  • 1
    Have a look at type evidences. Basically they allow you to tell the compiler "I promise you this value is of this type". Maybe it could help you. They're many questions in SO explaining them, e.g. stackoverflow.com/questions/34499663/…. Commented Dec 19, 2018 at 13:51
  • 2
    So why is it called otherFoo not override foo? As I said, I think you need to explain your question more clearly so we can work out what you actually want to do. I'm sure we can help you, but you need to be clear on what it actually is that you want. Commented Dec 19, 2018 at 13:58

1 Answer 1

1

What you are asking to do is something like this:

trait Foo {
  def foo[T <: MyBaseConfiguration](config: T) = {
    println("do smething")
    println(config.configValue)
  }
}

class Foo2 extends Foo {
  override def foo[T <: MyOtherConfiguration](c: T) = {
    println("do smething else")
    println(c.configValue)
    println(c.otherValue)
  }
}

However this will not work because it breaks type safety. Consider the following:

class MyThirdConfiguration extends MyBaseConfiguration {...}

val foo2: Foo = new Foo2
val cfg: MyBaseConfiguration = new MyThirdConfiguration

foo2.foo(cfg)

foo2 is an instance of Foo2 but looks like a Foo. cfg is an instance of MyThirdConfiguration but looks like MyBaseConfiguration. So foo2.foo(cfg) is calling Foo2.foo with an object that is not MyOtherConfiguration and doesn't have the extra fields, even though the types match.

Note that Foo2.foo could be defined to take a superclass of MyBaseConfiguration because this would not break type safety.

Also note that result types for overloaded functions work the other way round. You can return a subclass of the type returned by the base function but not a superclass because the former is type safe but the latter is not.

Sign up to request clarification or add additional context in comments.

3 Comments

But class Foo2 extends Foo { override def foo will not compile (as you mention) so if I remove extends/override the following: val foo2: Foo = new Foo2 will no longer compile. Am I missing something here?
@GeorgHeiler I don't think you are missing anything, I was just explaining why what you want to do doesn't work. So, yes, the code doesn't compile because it would be dangerous if it did! It may be possible to do what you want to do but I am still not clear what exactly it is that you want to do.
Your extended example code is exactly what I want to perform. I have an interface with various implementations. The interface defines a function which additionally gets some input. However the input (named configuration above) changes per implementation of the interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.