2

I am new to Scala. I have a Class A that extends a Class C. I also have a Class B that also extends a Class C

I want function objects of type A->B to extend C as well (and also other derived types, such as A->(A->B)). But I read in "Programming in scala" following:

A function literal is compiled into a class that when instantiated at runtime is a function value.

Is there some way of automatically letting A->B extend C, other then manually having to create a new class that represents the function?

vindev
  • 2,240
  • 2
  • 13
  • 20
  • Unfortunately I haven't solved the problem yet. Your answer contains many new topics for me on which I first have to read up. Also, this project is just a side project and I haven't had much time to work on it lately. Sorry! – user3068137 Feb 01 '18 at 14:54
  • No problem, as long as it helped. – slouc Jun 18 '18 at 22:03

1 Answers1

2

Functions in Scala are modelled via FunctionN trait. For example, simple one-input-one-output functions are all instances of the following trait:

trait Function1[-T1, +R] extends AnyRef

So what you're asking is "how can I make instances of Function also become subclasses of C". This is not doable via standard subtyping / inheritance, because obviously we can't modify the Function1 trait to make it extend your custom class C. Sure, we could make up a new class to represent the function as you suggested, but that will only take us so far and it's not so easy to implement, not to mention that any function you want to use as C will have to be converted to your pseudo-function trait first, which will make things horrible.

What we can do, however, is create a typeclass which then contains an implementation for A -> B, among others.

Let's take the following code as example:

trait A
trait B
trait C[T]

object C {
  implicit val fa = new C[A] {}
  implicit val fb = new C[B] {}
  implicit val fab = new C[Function1[A, B]] {}
}


object Test extends scala.App {

  val f: A => B = (a: A) => new B {}

  def someMethod[Something: C](s: Something) = {
    // uses "s", for example:
    println(s)
  }

  someMethod(f) // Test$$$Lambda$6/1744347043@dfd3711

}

You haven't specified your motivation for making A -> B extend C, but obviously you want to be able to put A, B and A -> B under the "same umbrella" because you have, say, some method (called someMethod) which takes a C so with inheritance you can pass it values of type A, B or A -> B.

With a typeclass you achieve the same thing, with some extra advantages, such as e.g. adding D to the family one day without changing existing code (you would just need to implement an implicit value of type C[D] somewhere in scope).

So instead of having someMethod take instances of C, it simply takes something (let's call it s) of some type (let's call it Something), with the constraint that C[Something] must exist. If you pass something for which an instance of C doesn't exist, you will get an error:

trait NotC
someMethod(new NotC {}) 
// Error: could not find implicit value for evidence parameter of type C[NotC]

You achieve the same thing - you have a family of C whose members are A, B and A => B, but you go around subtyping problems.

slouc
  • 9,508
  • 3
  • 16
  • 41
  • I managed to get a first working version with this, thank you. I still have some questions about it though: – user3068137 Sep 03 '18 at 12:18
  • @user3068137 What questions? – slouc Sep 03 '18 at 14:54
  • I posted them as an answer because it exceeded the max amount of characters for a comment. But now this answer has been deleted. What should I do? – user3068137 Sep 04 '18 at 12:13
  • What is the return type of the method someMethod? I would like to call someMethod multiple times, to retrieve the values and store them in a set. But this Set would then contain items of different types, all kinds that extend C, like A, B , A->B and A->(A->B). How can I do this? – user3068137 Sep 05 '18 at 09:32
  • It would contain elements of type "some T for which Something[T] exists". Return type of someMethod() in this example is just a Unit because it simply prints out the element. – slouc Sep 05 '18 at 09:49
  • I meant to say: If I want the method someMethod to return the s of type Something, how should I write the return type. Because if I use Something as return type and I try to assign it to a value, I get the error that the types do not conform. I want to extract the value (which is of either type A, type B or type A->B) out with this method someMethod, but I cannot get it to work. – user3068137 Sep 05 '18 at 13:11