Phantom types and the Required class

13 views
Skip to first unread message

Adam Warski

unread,
Jan 22, 2014, 9:03:15 AM1/22/14
to rogue...@googlegroups.com
Hello,

I was looking in more detail at the usage of phantom types in Rogue and I'm wondering about the role of the Required class and its type parameters.
E.g. for AddOrder we have:

trait AddOrder[-In, +Out] extends Required[In, Unordered]
object AddOrder {
  implicit def addOrder[Rest >: Sel with Lim with Sk with Or with Sh]: AddOrder[Rest with Unordered, Rest with Ordered] = null
}

where Required is:

class Required[-A, +B] {
  def apply[M, R](q: Query[M, R, A]): Query[M, R, B] = q.asInstanceOf[Query[M, R, B]]
}

Isn't there a constraint missing that A should be a subclass of B or similar? Usage of Required would suggest such intention.

The checks still work due to the addOrder definition (In is required to be Unordered), so it's not really a bug, just wondering
However, you can create a new AddOrder[Ordered, Ordered] instance ;)

-- 
Adam


Jason Liszka

unread,
Jan 22, 2014, 4:36:46 PM1/22/14
to rogue...@googlegroups.com
Required is a reimplementation of <:< (from the Prelude). I wanted AddOrder[-In, +Out] to also enforce that In <: Unordered (it wouldn't make sense to add Ordered to something that was already Ordered). I could do that with 2 implicits at every call site (one to check In <:< Ordered and one to AddOrder), but I thought I could save some work by folding the <:< check into AddOrder, in other words, makin AddOrder[-In, +Out] extend In <:< Unordered. But <:< is sealed, so I had to reimplement it, and I called it Required. I suppose you could constrain A <: B, but Prelude doesn't, and I just copied that.

You could create an AddOrder[Ordered, Ordered] instance, but it wouldn't be that useful... AddOrder[A, B] is a type relation between type A and type B. So AddOrder[Ordered, Ordered] is essentially the identity function from Ordered to Ordered.

Add* is only intended to be used by name within the rogue package. Users of rogue should not ever need to create their own instances.

Hope that helps!


--
You received this message because you are subscribed to the Google Groups "rogue-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rogue-users...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Adam Warski

unread,
Jan 24, 2014, 9:33:32 AM1/24/14
to rogue...@googlegroups.com
Required is a reimplementation of <:< (from the Prelude). I wanted AddOrder[-In, +Out] to also enforce that In <: Unordered (it wouldn't make sense to add Ordered to something that was already Ordered). I could do that with 2 implicits at every call site (one to check In <:< Ordered and one to AddOrder), but I thought I could save some work by folding the <:< check into AddOrder, in other words, makin AddOrder[-In, +Out] extend In <:< Unordered. But <:< is sealed, so I had to reimplement it, and I called it Required. I suppose you could constrain A <: B, but Prelude doesn't, and I just copied that.

Ah, I see. I alse did a usage search on Required which helped :)

However, is the fact that e.g. AddOrder extends Required ever used? As for implicit usage of Required in e.g. Query, I think the Required.conforms implicit kicks in. And for the AddOrder.addOrder implicit, what implicits create the Required instance doesn’t matter, right?  

You could create an AddOrder[Ordered, Ordered] instance, but it wouldn't be that useful... AddOrder[A, B] is a type relation between type A and type B. So AddOrder[Ordered, Ordered] is essentially the identity function from Ordered to Ordered.

Sure, I was wondering more academically, if this should be possible or not.

Thanks for the explanations,
Adam


Jason Liszka

unread,
Feb 7, 2014, 4:26:20 PM2/7/14
to rogue...@googlegroups.com
However, is the fact that e.g. AddOrder extends Required ever used?

Yes, it's used to enforce that In <: Unordered and to replace Unordered with Ordered in one go. I could do it with 2 separate implicits, but this just saved typing.


Adam Warski

unread,
Feb 10, 2014, 3:30:52 AM2/10/14
to rogue...@googlegroups.com

On 07 Feb 2014, at 22:26, Jason Liszka <jli...@foursquare.com> wrote:

However, is the fact that e.g. AddOrder extends Required ever used?

Yes, it's used to enforce that In <: Unordered and to replace Unordered with Ordered in one go. I could do it with 2 separate implicits, but this just saved typing.

But the two type parameters of Required (Required[-A, +B]) are not bound in any way - the fact that AddOrder[-In, +Out] extends Required[In, Unordered] doesn’t really put any constraints on In and Out?

Jason Liszka

unread,
Feb 10, 2014, 11:10:31 AM2/10/14
to rogue...@googlegroups.com
The constraints are in which instances of Required[A, B] are implicitly available. The idea is that we only generate instances of Required[A, A] for any A, and we only generate instances of AddOrder[In, Out] for specific Ins and Outs.

There aren't really type constraints on In and Out that make sense, but yes, you could specify A <: B.


Adam Warski

unread,
Feb 10, 2014, 3:23:20 PM2/10/14
to rogue...@googlegroups.com
But if:

trait AddOrder[-In, +Out] extends Required[In, Unordered]

then any instance of AddOrder is also an instance of Required, regardless of what implicits there are available directly for required (there’s not implicit Required lookup here). But maybe I’ve been looking at that code for too long ;)

Adam

You received this message because you are subscribed to a topic in the Google Groups "rogue-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rogue-users/H-FyjIe-xlU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rogue-users...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.

Jason Liszka

unread,
Feb 10, 2014, 4:01:09 PM2/10/14
to rogue...@googlegroups.com
Hm, yeah, I guess it is redundant, because we are only making instances of AddOrder where In <: Unordered.

trait AddOrder[-In, +Out] extends Required[In, Unordered]
object AddOrder {
  implicit def addOrder[Rest >: Sel with Lim with Sk with Or with Sh]: AddOrder[Rest with Unordered, Rest with Ordered] = null
}

One other thing is that Required[A, B] supplies a coercion method that you can use to safely cast a Query[M, R, A] to a Query[M, R, B]. Not sure if that is used anywhere, though... been a while since I looked at it.

Adam Warski

unread,
Feb 11, 2014, 3:10:26 AM2/11/14
to rogue...@googlegroups.com
Ok, clear now, thanks for taking the time! :)

Adam
Reply all
Reply to author
Forward
0 new messages