Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Path-dependent types without a path?

Consider this trivial example:

class Outer {
  case class Inner()
  def test(i: Inner) = {}
}

As expected, this doesn't compile because of a type mismatch:

val o1 = new Outer()
val o2 = new Outer()

o1.test(o2.Inner())  // doesn't compile

What if we want to define a standalone function?

This is no good

def test[X <: Outer](a: X#Inner, b: X#Inner) = {}

because this compiles as if everything is OK

test(o1.Inner(), o2.Inner())

This works

def test(x: Outer)(a: x.Inner, b: x.Inner) = {}

because this compiles:

test(o1)(o1.Inner(), o1.Inner())

and this doesn't:

test(o1)(o1.Inner(), o2.Inner())

However we have to pass an extra Outer argument to test. Is it possible to avoid this? Ideally, the following should work:

test(o1.Inner(), o1.Inner()) // ok
test(o1.Inner(), o2.Inner()) // compilation error
like image 548
n. 1.8e9-where's-my-share m. Avatar asked Jun 16 '17 11:06

n. 1.8e9-where's-my-share m.


People also ask

What are the different types of path-dependent options?

There are many types of path-dependent options including Asian, chooser, lookback, and barrier options. A soft path dependent option bases its value on a single price event that occurred during the life of the option.

What is path dependence?

Path dependence is when the decisions presented to people are dependent on previous decisions or experiences made in the past.

What is the difference between soft path dependent and hard path dependent?

A soft path dependent option bases its value on a single price event that occurred during the life of the option. A hard path dependent option takes into account the entire trading history of the underlying asset.

What is path-dependent analysis?

Path dependence has primarily been used in comparative-historical analyses of the development and persistence of institutions, whether they be social, political, or cultural. There are arguably two types of path-dependent processes:


1 Answers

I don't think that, out of the box, it's possible to enforce it in a satisfying way. For instance, one possible solution might be:

scala> def test[X <: Outer#Inner](a: X)(b: X) = ()
test: [X <: Outer#Inner](a: X)(b: X)Unit

scala> test(o1.Inner())(o1.Inner())

scala> test(o1.Inner())(o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test(o1.Inner())(o2.Inner())
                                ^

Looks good, but you can circumvent it by explicitly passing in the type arguments. (same goes for @OlivierBlanvillain's solution by the way)

scala> test[Outer#Inner](o1.Inner())(o2.Inner())

Now let's try the following:

scala> def test[X <: Outer](a: X#Inner)(b: X#Inner) = ()
test: [X <: Outer](a: X#Inner)(b: X#Inner)Unit

scala> test(o1.Inner())(o2.Inner())

Doesn't work, scalac infers X to be Outer, which isn't specific enough, and we could supply Outer as explicit type argument anyway. We need a way to force X to be a singleton type so that it can only represent the path o1 or o2, and not some general type that can be inhabited by an infinite amount of values. There is a way. Scala has the marker trait Singleton for this purpose. Let's try it:

scala> def test[X <: Outer with Singleton](a: X#Inner)(b: X#Inner) = ()
test: [X <: Outer with Singleton](a: X#Inner)(b: X#Inner)Unit

scala> test(o1.Inner())(o1.Inner())
<console>:15: error: inferred type arguments [Outer] do not conform to method test's type parameter bounds [X <: Outer with Singleton]
       test(o1.Inner())(o1.Inner())
       ^
<console>:15: error: type mismatch;
 found   : o1.Inner
 required: X#Inner
       test(o1.Inner())(o1.Inner())
                    ^

Now our valid case doesn't work anymore! The problem is that scalac refuses to infer singleton types. We have to pass them in explicitly:

scala> test[o1.type](o1.Inner())(o1.Inner())

The invalid cases don't work anymore:

scala> test(o1.Inner())(o2.Inner())
<console>:16: error: inferred type arguments [Outer] do not conform to method test's type parameter bounds [X <: Outer with Singleton]
       test(o1.Inner())(o2.Inner())
       ^
<console>:16: error: type mismatch;
 found   : o1.Inner
 required: X#Inner
       test(o1.Inner())(o2.Inner())
                    ^

scala> test[o1.type](o1.Inner())(o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test[o1.type](o1.Inner())(o2.Inner())
                                         ^

scala> test[Outer](o1.Inner())(o2.Inner())
<console>:17: error: type arguments [Outer] do not conform to method test's type parameter bounds [X <: Outer with Singleton]
       test[Outer](o1.Inner())(o2.Inner())
           ^

So this enforces the rules we want, but you have to pass in the types explicitly...


EDIT

Actually it turns out you can enforce this without losing type inference and without help from any external libraries, but you're probably not going to like it :-p

META EDIT as pointed out in the comments this can still be circumvented if you try hard enough, so I guess you're stuck with the above solution.

scala> import scala.language.existentials
import scala.language.existentials

scala> def test[X <: x.Inner forSome { val x: Outer }](a: X, b: X) = ()
test: [X <: x.Inner forSome { val x: Outer }](a: X, b: X)Unit

scala> test(o1.Inner(), o1.Inner())

scala> test(o1.Inner(), o2.Inner())
<console>:16: error: inferred type arguments [Outer#Inner] do not conform to method test's type parameter bounds [X <: x.Inner forSome { val x: Outer }]
       test(o1.Inner(), o2.Inner())
       ^
<console>:16: error: type mismatch;
 found   : o1.Inner
 required: X
       test(o1.Inner(), o2.Inner())
                    ^
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: X
       test(o1.Inner(), o2.Inner())
                                ^

scala> test[o1.Inner](o1.Inner(), o2.Inner())
<console>:16: error: type mismatch;
 found   : o2.Inner
 required: o1.Inner
       test[o1.Inner](o1.Inner(), o2.Inner())
                                          ^
like image 140
Jasper-M Avatar answered Sep 22 '22 17:09

Jasper-M