Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala method that needs either one of two implicit parameters

I'm interested if I can create method with similar idea:

def myMethod[T](param: T)(implicit oneOf: Either[TypeClass1[T], TypeClass2[T]]) = oneOf match ...

I've tried to use default parameters (I've seen somethin similar in akka):

def myMethod[T](param: T)(implicit t1: TypeClass1[T] = null, t2: TypeClass2[T] = null) = 
  if (t1 == null) ...

However, that way I cannot force scala compiler to find at least one of them.

Also, I've implemented implicit conversion from TypeClass1[T] to Left[TypeClass1[T], TypeClass2[T]] and from TC2 to Right, however Scala compiler ignores this conversions.

Is there any way to do something like this?

like image 304
Yevhenii Popadiuk Avatar asked Dec 02 '22 09:12

Yevhenii Popadiuk


2 Answers

The obvious solution is to create a new typeclass that can be constructed using either TypeClass1 or TypeClass2. The new typeclass implements the functionality used by myMethod that is common to both and maps it to the appropriate methods on TypeClass1 or TypeClass2.


Here is an example:

  trait TypeClass1[T] {
    def showOne = println("Typeclass 1")
  }

  trait TypeClass2[T] {
    def showTwo = println("Typeclass 2")
  }

  trait UnionTypeClass[T] {
    def show
  }

  object UnionTypeClass {
    implicit def t1[T](implicit ev: TypeClass1[T]) = new UnionTypeClass[T] {
      def show = ev.showOne
    }

    implicit def t2[T](implicit ev: TypeClass2[T]) = new UnionTypeClass[T] {
      def show = ev.showTwo
    }
  }


  implicit object IntClass extends TypeClass1[Int]
  implicit object StringClass extends TypeClass2[String]


  def myMethod[T](param: T)(implicit ev: UnionTypeClass[T]) = {
    ev.show
  }

  myMethod(0)
  myMethod("hello")

This will print

Typeclass 1
Typeclass 2
like image 102
Tim Avatar answered Jun 02 '23 02:06

Tim


In Scala 3 you might be able to use union type like so

trait Foo[A]
trait Bar[A]

given foo as Foo[Int] {}

def g[T](using Foo[T] | Bar[T]) = summon
foo[Int] // ok
like image 25
Mario Galic Avatar answered Jun 02 '23 04:06

Mario Galic