- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Expressing "use companion method" in a hierarchy ?
Mon, 2012-02-13, 16:03
Hello guys,
I have a problem where I have a bunch of case classes used to classify items.
Items have a key type statically defined on their companion object, so that they look like:
======================
trait ItemKey
trait Item { def key : ItemKey }
object A { def key = keyX }
case class A { def key = A.key }
object B { def key = keyY }
case class B { def key = B.key }
======================
etc
That leads to a bunch of code boilerplate (even more than in that simplified example), that in turns lead to silly errors (copy past with the bad object name, special case where the key is not in the companion are hidden in the mass, etc).
I really would be able to express in the Item trait "use the method 'key' defined in the companion object of that class".
=========
trait Item { def key : ItemKey = ??companion??.key }
=========
Is this possible ? If not, is there a classical solution to that ?
Having a common trait for both object A and its companion does not seems better, as it tends to add even more boilerplate (for case class/object pair, we have a third trait to define (ok, with two methods less), but as said before, we have dozens of these pairs, with multiple keys to define and so with multiple common trait, so a cheaper (in line of code) solution would be great !)
Thanks,
-- Francois ARMAND http://fanf42.blogspot.com http://www.normation.com
Mon, 2012-02-13, 18:11
#2
Re: Expressing "use companion method" in a hierarchy ?
+Long.MAX_VALUE
You already have me drooling at the possibilities, it would bring me one happy step closer in my nefarious plans for world domination :)
On 13 February 2012 15:52, Paul Phillips <paulp@improving.org> wrote:
You already have me drooling at the possibilities, it would bring me one happy step closer in my nefarious plans for world domination :)
On 13 February 2012 15:52, Paul Phillips <paulp@improving.org> wrote:
[Moved from scala-user.]
I run into this all the time and I don't know how to deal with it without language support.
Internally, the compiler has a very strong, specific, articulated idea of the link between a class and its companion object. We should expose that link.
Right now there is no way to express, given some unknown T, "the type of T's companion." It would be VERY USEFUL if there was! One can use reflection to acquire the companion instance, but that is a far cry from a static compiler-enforced relationship. It would be even more useful if one could also make reference to the types of all the companions of one's parents (the "inherited companions".)
I can imagine using manifests for this, so that if one wanted to call companion.method, a manifest would be required which assured that the companion had such a method. (How to arrange dispatch so that one could generically call methods in the inherited companions I don't know offhand.) But I'm infinitely flexible on the technique, it's the result I'm after.
On Mon, Feb 13, 2012 at 7:03 AM, Francois <fanf42@gmail.com> wrote:
Hello guys,
I have a problem where I have a bunch of case classes used to classify items.
Items have a key type statically defined on their companion object, so that they look like:
======================
trait ItemKey
trait Item { def key : ItemKey }
object A { def key = keyX }
case class A { def key = A.key }
object B { def key = keyY }
case class B { def key = B.key }
======================
etc
That leads to a bunch of code boilerplate (even more than in that simplified example), that in turns lead to silly errors (copy past with the bad object name, special case where the key is not in the companion are hidden in the mass, etc).
I really would be able to express in the Item trait "use the method 'key' defined in the companion object of that class".
=========
trait Item { def key : ItemKey = ??companion??.key }
=========
Is this possible ? If not, is there a classical solution to that ?
Having a common trait for both object A and its companion does not seems better, as it tends to add even more boilerplate (for case class/object pair, we have a third trait to define (ok, with two methods less), but as said before, we have dozens of these pairs, with multiple keys to define and so with multiple common trait, so a cheaper (in line of code) solution would be great !)
Thanks,
-- Francois ARMAND http://fanf42.blogspot.com http://www.normation.com
Mon, 2012-02-13, 20:21
#3
Re: Expressing "use companion method" in a hierarchy ?
On Mon, Feb 13, 2012 at 3:52 PM, Paul Phillips wrote:
> I run into this all the time and I don't know how to deal with it without
> language support.
There is a current-Scala (at least partial) solution to this though:
if each companion object publishes itself implicitly, then classes can
resolve their corresponding object implicitly using shared
infrastructure. Here's how it looks for Francois's problem ...
We need a common interface for all companions,
trait StaticKey {
def key : String
}
and a box to put the companion object in,
case class Companion[-C, T](t : T)
then we can implement the companion objects like so,
object A extends StaticKey {
val key = "KeyA"
// Self-publish as a StaticKey
implicit val companion = Companion[A, StaticKey](this)
}
object B extends StaticKey {
val key = "KeyB"
// Self-publish as a StaticKey
implicit val companion = Companion[B, StaticKey](this)
}
Some common infrastructure for the classes/traits,
trait Item {
// Resolve reference to companion implicitly ... note use of this.type
def key(implicit c : Companion[this.type, StaticKey]) = c.t.key
}
And we're done,
class A extends Item
class B extends Item
object TestKey extends App {
val a = new A
assert(a.key eq A.key)
val b = new B
assert(b.key eq B.key)
}
Gist here: http://goo.gl/oJ5Tt
Cheers,
Miles
Mon, 2012-02-13, 20:41
#4
Re: Expressing "use companion method" in a hierarchy ?
On Mon, Feb 13, 2012 at 11:11 AM, Miles Sabin <miles@milessabin.com> wrote:
There is a current-Scala (at least partial) solution to this though:
if each companion object publishes itself implicitly, then classes can
resolve their corresponding object implicitly using shared
infrastructure.
This does not meet my definition of partial solution. It is just something else. One should not have to establish and utilize implicit infrastructure to tell the compiler something it already knows. We're not talking about some obscure construct here, it's the companion object. It's fundamental.
Analogy time: what if "this.type" wasn't built in, and you had to take some positive action in every class in which you wanted to use it.
trait HasThisType[T] { type ThisType = T with Singleton }
class MyClass extends HasThisType[MyClass] { def bippy(): ThisType = this }
Kind of hard to imagine moving in that direction, isn't it? But "companion.type" would be a lot more useful than this.type is. If we had "companion.type" right now, taking away the ability to reference "companion.type" would sound at least as ridiculous as removing this.type. (Rather more so, I think.)
Mon, 2012-02-13, 20:41
#5
Re: Expressing "use companion method" in a hierarchy ?
On Mon, Feb 13, 2012 at 7:30 PM, Paul Phillips wrote:
> This does not meet my definition of partial solution. It is just something
> else.
Fair enough, and FTR I agree.
Nevertheless, it might be a workable solution for Francois's specific problem.
Cheers,
Miles
Mon, 2012-02-13, 20:51
#6
Re: Expressing "use companion method" in a hierarchy ?
On Mon, Feb 13, 2012 at 7:11 PM, Miles Sabin wrote:
> There is a current-Scala (at least partial) solution to this though:
> if each companion object publishes itself implicitly, then classes can
> resolve their corresponding object implicitly using shared
> infrastructure. Here's how it looks for Francois's problem ...
And actually we can factor out a lot of the companion object side
boilerplate as well,
trait Publish[C, T] { self : T =>
implicit val companion = Companion[C, T](this)
}
object A extends StaticKey with Publish[A, StaticKey] {
val key = "KeyA"
}
object B extends StaticKey with Publish[B, StaticKey] {
val key = "KeyB"
}
Everything else the same. I've updated the gist here: http://goo.gl/oJ5Tt
Cheers,
Miles
Mon, 2012-02-13, 23:11
#7
Re: Expressing "use companion method" in a hierarchy ?
This is great scala-fu, Miles.
Regarding Paul's wishes I am thinking about following: It would be nice
to be able to access a companion object from any instance like
.object. It would deliver the companion object of the
's runtime class (more precisely "last" non-anonymous class).
The type would be AnyRef (if not constrained, bellow) and the value
would be null if the class of the doesn't have companion
object. It would be possible to request that the companion object must
conform to a given type like this (similar to self type):
trait A { object: StaticKey =>
def key = object.key // shortcut for this.object.key
}
For each non-abstract class the constraints on the companion object from
all super-classes/traits (including itself) would have to be fulfilled.
If the is an object then the .object is the
instance itself (e.g. inside the object definition).
I can't access (name) companion object(s) of the super-classes (other
than explicitly naming them), e.g. this.object and super.object is the
same companion instance (possibly with weaker constraints on super.object).
Perhaps this is too wild. Do you have a different proposal?
With regards,
Jan
On 13.02.2012 20:11, Miles Sabin wrote:
> On Mon, Feb 13, 2012 at 3:52 PM, Paul Phillips wrote:
>> I run into this all the time and I don't know how to deal with it without
>> language support.
> There is a current-Scala (at least partial) solution to this though:
> if each companion object publishes itself implicitly, then classes can
> resolve their corresponding object implicitly using shared
> infrastructure. Here's how it looks for Francois's problem ...
>
> We need a common interface for all companions,
>
> trait StaticKey {
> def key : String
> }
>
> and a box to put the companion object in,
>
> case class Companion[-C, T](t : T)
>
> then we can implement the companion objects like so,
>
> object A extends StaticKey {
> val key = "KeyA"
>
> // Self-publish as a StaticKey
> implicit val companion = Companion[A, StaticKey](this)
> }
>
> object B extends StaticKey {
> val key = "KeyB"
>
> // Self-publish as a StaticKey
> implicit val companion = Companion[B, StaticKey](this)
> }
>
> Some common infrastructure for the classes/traits,
>
> trait Item {
> // Resolve reference to companion implicitly ... note use of this.type
> def key(implicit c : Companion[this.type, StaticKey]) = c.t.key
> }
>
> And we're done,
>
> class A extends Item
>
> class B extends Item
>
> object TestKey extends App {
> val a = new A
> assert(a.key eq A.key)
>
> val b = new B
> assert(b.key eq B.key)
> }
>
> Gist here: http://goo.gl/oJ5Tt
>
> Cheers,
>
>
> Miles
>
Tue, 2012-02-14, 20:01
#8
Re: Expressing "use companion method" in a hierarchy ?
Hi Francois,
as there is no language construct to retain the companion object of a
given class at compile time, I'd simply recommend you directly
incorporating "key" in your classes even if its constant with regard
to class instances like
class A extends Item { def key = }
Why do you feel uncomfortable with above?
Peter
Wed, 2012-02-15, 06:11
#9
Re: Expressing "use companion method" in a hierarchy ?
I've been wanting this feature since the first time I ever heard about companion objects (along with the ability to get the companion for an instance.) It is absolutely something worth exposing.
Kris
Kris
Wed, 2012-02-15, 17:01
#10
Re: Re: Expressing "use companion method" in a hierarchy ?
Given that a fair volume of non-trivial Scala code goes to great lengths to expose companions, I tend to agree that this is a feature worth baking into the language. I'm thinking of collections specifically, which are my benchmark for non-triviality.
Daniel
On Tue, Feb 14, 2012 at 11:07 PM, nuttycom <kris.nuttycombe@gmail.com> wrote:
Daniel
On Tue, Feb 14, 2012 at 11:07 PM, nuttycom <kris.nuttycombe@gmail.com> wrote:
I've been wanting this feature since the first time I ever heard about companion objects (along with the ability to get the companion for an instance.) It is absolutely something worth exposing.
Kris
Wed, 2012-02-15, 19:11
#11
Re: Re: Expressing "use companion method" in a hierarchy ?
I like ".object". This is my awful/awesome hack:
// Concrete implementations are all case classestrait SearchStrategy { type C <: SearchStrategyCompanion
def companion: C // ...}
trait SearchStrategyCompanion { type S <: SearchStrategy
// ... // this method is implemented by the compiler! // (i.e. it's the Strategy case class constructor :) def apply(searchDirectoryUris: Seq[URI], properties: Map[String, String]): S }
-0xe1a
// Concrete implementations are all case classestrait SearchStrategy { type C <: SearchStrategyCompanion
def companion: C // ...}
trait SearchStrategyCompanion { type S <: SearchStrategy
// ... // this method is implemented by the compiler! // (i.e. it's the Strategy case class constructor :) def apply(searchDirectoryUris: Seq[URI], properties: Map[String, String]): S }
-0xe1a
Thu, 2012-02-16, 04:11
#12
Re: Expressing "use companion method" in a hierarchy ?
What I don't like about the proposal is that it is more like a
counter-measure instead of a measure. It exposes something hidden.
Library can fight deficiencies in the language but language should not
fight itself.
The object conflates its definition/class and its slot/instance. I don't
know how but it might be good to separate them, provide means for
defining "object/companion" slots, and use current class/trait semantics
for the definition + syntactic sugar. It might be conceptually simpler.
This is just too early and might be very wrong.
Thu, 2012-02-16, 09:01
#13
Re: Expressing "use companion method" in a hierarchy ?
Going to add my voice to the chorus: I would also find it very useful to have "companion type" and "companion instance" be supported by the language.
--j
On Mon, Feb 13, 2012 at 10:52 AM, Paul Phillips <paulp@improving.org> wrote:
--j
On Mon, Feb 13, 2012 at 10:52 AM, Paul Phillips <paulp@improving.org> wrote:
[Moved from scala-user.]
I run into this all the time and I don't know how to deal with it without language support.
Internally, the compiler has a very strong, specific, articulated idea of the link between a class and its companion object. We should expose that link.
Right now there is no way to express, given some unknown T, "the type of T's companion." It would be VERY USEFUL if there was! One can use reflection to acquire the companion instance, but that is a far cry from a static compiler-enforced relationship. It would be even more useful if one could also make reference to the types of all the companions of one's parents (the "inherited companions".)
I can imagine using manifests for this, so that if one wanted to call companion.method, a manifest would be required which assured that the companion had such a method. (How to arrange dispatch so that one could generically call methods in the inherited companions I don't know offhand.) But I'm infinitely flexible on the technique, it's the result I'm after.
On Mon, Feb 13, 2012 at 7:03 AM, Francois <fanf42@gmail.com> wrote:
Hello guys,
I have a problem where I have a bunch of case classes used to classify items.
Items have a key type statically defined on their companion object, so that they look like:
======================
trait ItemKey
trait Item { def key : ItemKey }
object A { def key = keyX }
case class A { def key = A.key }
object B { def key = keyY }
case class B { def key = B.key }
======================
etc
That leads to a bunch of code boilerplate (even more than in that simplified example), that in turns lead to silly errors (copy past with the bad object name, special case where the key is not in the companion are hidden in the mass, etc).
I really would be able to express in the Item trait "use the method 'key' defined in the companion object of that class".
=========
trait Item { def key : ItemKey = ??companion??.key }
=========
Is this possible ? If not, is there a classical solution to that ?
Having a common trait for both object A and its companion does not seems better, as it tends to add even more boilerplate (for case class/object pair, we have a third trait to define (ok, with two methods less), but as said before, we have dozens of these pairs, with multiple keys to define and so with multiple common trait, so a cheaper (in line of code) solution would be great !)
Thanks,
-- Francois ARMAND http://fanf42.blogspot.com http://www.normation.com
Thu, 2012-02-16, 09:41
#14
Re: Expressing "use companion method" in a hierarchy ?
I agree it's useful. But it will also add one or two things to the
type system. And the bar is extremely high for that. Generally, I
would much prefer making the type system simpler than adding stuff to
it.
Cheers
Thu, 2012-02-16, 14:11
#15
Re: Expressing "use companion method" in a hierarchy ?
If the compiler has a notion about the link between a class and its
companion object and reducing boiler plate code is the goal then it
sounds to me like a perfect use case for scala macros, but maybe
Eugene can comment on that.
On 13 feb, 16:52, Paul Phillips wrote:
> [Moved from scala-user.]
>
> I run into this all the time and I don't know how to deal with it without
> language support.
>
> Internally, the compiler has a very strong, specific, articulated idea of
> the link between a class and its companion object. We should expose that
> link.
>
> Right now there is no way to express, given some unknown T, "the type of
> T's companion." It would be VERY USEFUL if there was! One can use
> reflection to acquire the companion instance, but that is a far cry from a
> static compiler-enforced relationship. It would be even more useful if one
> could also make reference to the types of all the companions of one's
> parents (the "inherited companions".)
>
> I can imagine using manifests for this, so that if one wanted to
> call companion.method, a manifest would be required which assured that the
> companion had such a method. (How to arrange dispatch so that one could
> generically call methods in the inherited companions I don't know offhand.)
> But I'm infinitely flexible on the technique, it's the result I'm after.
>
>
>
> On Mon, Feb 13, 2012 at 7:03 AM, Francois wrote:
>
> > Hello guys,
>
> > I have a problem where I have a bunch of case classes used to classify
> > items.
> > Items have a key type statically defined on their companion object, so
> > that they look like:
>
> > ======================
> > trait ItemKey
> > trait Item { def key : ItemKey }
>
> > object A { def key = keyX }
> > case class A { def key = A.key }
>
> > object B { def key = keyY }
> > case class B { def key = B.key }
> > ======================
> > etc
>
> > That leads to a bunch of code boilerplate (even more than in that
> > simplified example), that in turns lead to silly errors (copy past with the
> > bad object name, special case where the key is not in the companion are
> > hidden in the mass, etc).
>
> > I really would be able to express in the Item trait "use the method 'key'
> > defined in the companion object of that class".
>
> > =========
> > trait Item { def key : ItemKey = ??companion??.key }
> > =========
>
> > Is this possible ? If not, is there a classical solution to that ?
> > Having a common trait for both object A and its companion does not seems
> > better, as it tends to add even more boilerplate (for case class/object
> > pair, we have a third trait to define (ok, with two methods less), but as
> > said before, we have dozens of these pairs, with multiple keys to define
> > and so with multiple common trait, so a cheaper (in line of code) solution
> > would be great !)
>
> > Thanks,
>
> > --
> > Francois ARMANDhttp://fanf42.blogspot.comhttp://www.normation.com- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Thu, 2012-02-16, 14:21
#16
Re: Expressing "use companion method" in a hierarchy ?
Is there really any chance left to make the type system simpler at this point?
Thu, 2012-02-16, 18:01
#17
Re: Re: Expressing "use companion method" in a hierarchy ?
----
(Sent from my android)
On 16 בפבר 2012 15:10, "Dave" <dave.mahabiersing@hotmail.com> wrote:
>
> If the compiler has a notion about the link between a class and its
> companion object and reducing boiler plate code is the goal then it
> sounds to me like a perfect use case for scala macros, but maybe
> Eugene can comment on that.
I don't agree with this. It is such a useful thing that everyone will need to know how to use it. Then it is no different than making it part of the language, but less easy to use and maybe harder to develop. Since the information is already in the compiler it doesn't sound like there's something to gain in modularity either.
>
> On 13 feb, 16:52, Paul Phillips <pa...@improving.org> wrote:
> > [Moved from scala-user.]
> >
> > I run into this all the time and I don't know how to deal with it without
> > language support.
> >
> > Internally, the compiler has a very strong, specific, articulated idea of
> > the link between a class and its companion object. We should expose that
> > link.
> >
> > Right now there is no way to express, given some unknown T, "the type of
> > T's companion." It would be VERY USEFUL if there was! One can use
> > reflection to acquire the companion instance, but that is a far cry from a
> > static compiler-enforced relationship. It would be even more useful if one
> > could also make reference to the types of all the companions of one's
> > parents (the "inherited companions".)
> >
> > I can imagine using manifests for this, so that if one wanted to
> > call companion.method, a manifest would be required which assured that the
> > companion had such a method. (How to arrange dispatch so that one could
> > generically call methods in the inherited companions I don't know offhand.)
> > But I'm infinitely flexible on the technique, it's the result I'm after.
> >
> >
> >
> > On Mon, Feb 13, 2012 at 7:03 AM, Francois <fan...@gmail.com> wrote:
> >
> > > Hello guys,
> >
> > > I have a problem where I have a bunch of case classes used to classify
> > > items.
> > > Items have a key type statically defined on their companion object, so
> > > that they look like:
> >
> > > ======================
> > > trait ItemKey
> > > trait Item { def key : ItemKey }
> >
> > > object A { def key = keyX }
> > > case class A { def key = A.key }
> >
> > > object B { def key = keyY }
> > > case class B { def key = B.key }
> > > ======================
> > > etc
> >
> > > That leads to a bunch of code boilerplate (even more than in that
> > > simplified example), that in turns lead to silly errors (copy past with the
> > > bad object name, special case where the key is not in the companion are
> > > hidden in the mass, etc).
> >
> > > I really would be able to express in the Item trait "use the method 'key'
> > > defined in the companion object of that class".
> >
> > > =========
> > > trait Item { def key : ItemKey = ??companion??.key }
> > > =========
> >
> > > Is this possible ? If not, is there a classical solution to that ?
> > > Having a common trait for both object A and its companion does not seems
> > > better, as it tends to add even more boilerplate (for case class/object
> > > pair, we have a third trait to define (ok, with two methods less), but as
> > > said before, we have dozens of these pairs, with multiple keys to define
> > > and so with multiple common trait, so a cheaper (in line of code) solution
> > > would be great !)
> >
> > > Thanks,
> >
> > > --
> > > Francois ARMANDhttp://fanf42.blogspot.comhttp://www.normation.com- Tekst uit oorspronkelijk bericht niet weergeven -
> >
> > - Tekst uit oorspronkelijk bericht weergeven -
Thu, 2012-02-16, 18:11
#18
Re: Expressing "use companion method" in a hierarchy ?
Of particular concern to me is that (depending on implementation) it seems to provide another type-level mechanism for introducing cycles, giving us a second path to Turing Completeness. I can't find a way to actually exploit the cycle without relying on the "path dependent types of a path dependent type" trick (which is to say, the primary mechanism for fixpoint), but intuitively it feels like this should be possible. My original email on this thread was going to include a proof-of-concept showing how to do this, but I couldn't quite get it to work.
So in other words, I really like the idea of this feature (companion references) in practice, but I think Martin's concerns about extending the type system are very relevant here.
Daniel
On Thu, Feb 16, 2012 at 2:28 AM, martin odersky <martin.odersky@epfl.ch> wrote:
So in other words, I really like the idea of this feature (companion references) in practice, but I think Martin's concerns about extending the type system are very relevant here.
Daniel
On Thu, Feb 16, 2012 at 2:28 AM, martin odersky <martin.odersky@epfl.ch> wrote:
I agree it's useful. But it will also add one or two things to the
type system. And the bar is extremely high for that. Generally, I
would much prefer making the type system simpler than adding stuff to
it.
Cheers
Thu, 2012-02-16, 19:11
#19
Re: Expressing "use companion method" in a hierarchy ?
For the user
instead of
trait Item { def key : ItemKey = ??companion??.key }
it is something like:
trait Item { def key : ItemKey = @Companion key }
Doesn't look more difficult.
and macro annotation @Companion is predefined in the scala library so
the user doesn't have to implement that.
It takes the name of the current class (which is the same as the
companion object) and it takes the argument of the macro annotation
and creates the method to the companion object in the current class.
On 16 feb, 17:56, Ittay Dror wrote:
> ----
> (Sent from my android)
> On 16 בפבר 2012 15:10, "Dave" wrote:
>
>
>
> > If the compiler has a notion about the link between a class and its
> > companion object and reducing boiler plate code is the goal then it
> > sounds to me like a perfect use case for scala macros, but maybe
> > Eugene can comment on that.
>
> I don't agree with this. It is such a useful thing that everyone will need
> to know how to use it. Then it is no different than making it part of the
> language, but less easy to use and maybe harder to develop. Since the
> information is already in the compiler it doesn't sound like there's
> something to gain in modularity either.
>
>
>
>
>
>
>
> > On 13 feb, 16:52, Paul Phillips wrote:
> > > [Moved from scala-user.]
>
> > > I run into this all the time and I don't know how to deal with it
> without
> > > language support.
>
> > > Internally, the compiler has a very strong, specific, articulated idea
> of
> > > the link between a class and its companion object. We should expose
> that
> > > link.
>
> > > Right now there is no way to express, given some unknown T, "the type of
> > > T's companion." It would be VERY USEFUL if there was! One can use
> > > reflection to acquire the companion instance, but that is a far cry
> from a
> > > static compiler-enforced relationship. It would be even more useful if
> one
> > > could also make reference to the types of all the companions of one's
> > > parents (the "inherited companions".)
>
> > > I can imagine using manifests for this, so that if one wanted to
> > > call companion.method, a manifest would be required which assured that
> the
> > > companion had such a method. (How to arrange dispatch so that one could
> > > generically call methods in the inherited companions I don't know
> offhand.)
> > > But I'm infinitely flexible on the technique, it's the result I'm after.
>
> > > On Mon, Feb 13, 2012 at 7:03 AM, Francois wrote:
>
> > > > Hello guys,
>
> > > > I have a problem where I have a bunch of case classes used to classify
> > > > items.
> > > > Items have a key type statically defined on their companion object, so
> > > > that they look like:
>
> > > > ======================
> > > > trait ItemKey
> > > > trait Item { def key : ItemKey }
>
> > > > object A { def key = keyX }
> > > > case class A { def key = A.key }
>
> > > > object B { def key = keyY }
> > > > case class B { def key = B.key }
> > > > ======================
> > > > etc
>
> > > > That leads to a bunch of code boilerplate (even more than in that
> > > > simplified example), that in turns lead to silly errors (copy past
> with the
> > > > bad object name, special case where the key is not in the companion
> are
> > > > hidden in the mass, etc).
>
> > > > I really would be able to express in the Item trait "use the method
> 'key'
> > > > defined in the companion object of that class".
>
> > > > =========
> > > > trait Item { def key : ItemKey = ??companion??.key }
> > > > =========
>
> > > > Is this possible ? If not, is there a classical solution to that ?
> > > > Having a common trait for both object A and its companion does not
> seems
> > > > better, as it tends to add even more boilerplate (for case
> class/object
> > > > pair, we have a third trait to define (ok, with two methods less),
> but as
> > > > said before, we have dozens of these pairs, with multiple keys to
> define
> > > > and so with multiple common trait, so a cheaper (in line of code)
> solution
> > > > would be great !)
>
> > > > Thanks,
>
> > > > --
> > > > Francois ARMANDhttp://fanf42.blogspot.comhttp://www.normation.com-
>
> Tekst uit oorspronkelijk bericht niet weergeven -
>
>
>
>
>
> > > - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Thu, 2012-02-16, 20:31
#20
Re: Re: Expressing "use companion method" in a hierarchy ?
Hi Dave, I need to read about scala macros yet. What I'm trying to
understand is how would this work if you compile such trait/class
separately, without knowing the final class and its companion. How would
the typing be done or postponed and how would you handle the case where
the trait/class is extended by 2 classes whose companions provide
incompatible methods.
Regards,
Jan
On 16.02.2012 19:09, Dave wrote:
> For the user
>
> instead of
> trait Item { def key : ItemKey = ??companion??.key }
>
> it is something like:
>
> trait Item { def key : ItemKey = @Companion key }
>
> Doesn't look more difficult.
>
> and macro annotation @Companion is predefined in the scala library so
> the user doesn't have to implement that.
> It takes the name of the current class (which is the same as the
> companion object) and it takes the argument of the macro annotation
> and creates the method to the companion object in the current class.
>
>
>
>
> On 16 feb, 17:56, Ittay Dror wrote:
>> ----
>> (Sent from my android)
>> On 16 בפבר 2012 15:10, "Dave" wrote:
>>
>>
>>
>>> If the compiler has a notion about the link between a class and its
>>> companion object and reducing boiler plate code is the goal then it
>>> sounds to me like a perfect use case for scala macros, but maybe
>>> Eugene can comment on that.
>> I don't agree with this. It is such a useful thing that everyone will need
>> to know how to use it. Then it is no different than making it part of the
>> language, but less easy to use and maybe harder to develop. Since the
>> information is already in the compiler it doesn't sound like there's
>> something to gain in modularity either.
>>
>>
>>
>>
>>
>>
>>
>>> On 13 feb, 16:52, Paul Phillips wrote:
>>>> [Moved from scala-user.]
>>>> I run into this all the time and I don't know how to deal with it
>> without
>>>> language support.
>>>> Internally, the compiler has a very strong, specific, articulated idea
>> of
>>>> the link between a class and its companion object. We should expose
>> that
>>>> link.
>>>> Right now there is no way to express, given some unknown T, "the type of
>>>> T's companion." It would be VERY USEFUL if there was! One can use
>>>> reflection to acquire the companion instance, but that is a far cry
>> from a
>>>> static compiler-enforced relationship. It would be even more useful if
>> one
>>>> could also make reference to the types of all the companions of one's
>>>> parents (the "inherited companions".)
>>>> I can imagine using manifests for this, so that if one wanted to
>>>> call companion.method, a manifest would be required which assured that
>> the
>>>> companion had such a method. (How to arrange dispatch so that one could
>>>> generically call methods in the inherited companions I don't know
>> offhand.)
>>>> But I'm infinitely flexible on the technique, it's the result I'm after.
>>>> On Mon, Feb 13, 2012 at 7:03 AM, Francois wrote:
>>>>> Hello guys,
>>>>> I have a problem where I have a bunch of case classes used to classify
>>>>> items.
>>>>> Items have a key type statically defined on their companion object, so
>>>>> that they look like:
>>>>> ======================
>>>>> trait ItemKey
>>>>> trait Item { def key : ItemKey }
>>>>> object A { def key = keyX }
>>>>> case class A { def key = A.key }
>>>>> object B { def key = keyY }
>>>>> case class B { def key = B.key }
>>>>> ======================
>>>>> etc
>>>>> That leads to a bunch of code boilerplate (even more than in that
>>>>> simplified example), that in turns lead to silly errors (copy past
>> with the
>>>>> bad object name, special case where the key is not in the companion
>> are
>>>>> hidden in the mass, etc).
>>>>> I really would be able to express in the Item trait "use the method
>> 'key'
>>>>> defined in the companion object of that class".
>>>>> =========
>>>>> trait Item { def key : ItemKey = ??companion??.key }
>>>>> =========
>>>>> Is this possible ? If not, is there a classical solution to that ?
>>>>> Having a common trait for both object A and its companion does not
>> seems
>>>>> better, as it tends to add even more boilerplate (for case
>> class/object
>>>>> pair, we have a third trait to define (ok, with two methods less),
>> but as
>>>>> said before, we have dozens of these pairs, with multiple keys to
>> define
>>>>> and so with multiple common trait, so a cheaper (in line of code)
>> solution
>>>>> would be great !)
>>>>> Thanks,
>>>>> --
>>>>> Francois ARMANDhttp://fanf42.blogspot.comhttp://www.normation.com-
>> Tekst uit oorspronkelijk bericht niet weergeven -
>>
>>
>>
>>
>>
>>>> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>>
>> - Tekst uit oorspronkelijk bericht weergeven -
Thu, 2012-02-16, 21:11
#21
Re: Expressing "use companion method" in a hierarchy ?
The obvious implementation I thought about is basically just an
abstract method which the user can declare but cannot implement.
trait T {
object: CanSomething[T]
// is just
// def companion: CanSomething[T]
}
The AnyRef would provide:
object: AnyRef
The method would follow usual overriding rules.
Compiler would provide the implementation for each non-abstract class. If the class doesn't have companion object the implementation would return null, but it would only be allowed if there are no "override-declarations" of the "method".
There is no difference to current companion methods in the collection classes, apart from the fact that compiler would forcibly implement it. It is still necessary to say what the companion object needs to conform to, so the win is questionable.
One problem is when there is:
object A {
def foo = 1
}
class A {
def goo = object.foo // doesn't compile unless next line is uncommented
// object: { def foo: Int }
}
This is counter-intuitive. A solution attempt would be to automatically place such constraint on the companion object (in sub-classes and in current class) if the current companion object (of the class which uses object.<something>) has satisfying definition of <something>.
Anyway, "use companion method" is a fitting name of the thread :-) I suspect Francois it is not a coincidence.
What are other possible implementations?
With regards,
Jan
On 16.02.2012 18:03, Daniel Spiewak wrote:
trait T {
object: CanSomething[T]
// is just
// def companion: CanSomething[T]
}
The AnyRef would provide:
object: AnyRef
The method would follow usual overriding rules.
Compiler would provide the implementation for each non-abstract class. If the class doesn't have companion object the implementation would return null, but it would only be allowed if there are no "override-declarations" of the "method".
There is no difference to current companion methods in the collection classes, apart from the fact that compiler would forcibly implement it. It is still necessary to say what the companion object needs to conform to, so the win is questionable.
One problem is when there is:
object A {
def foo = 1
}
class A {
def goo = object.foo // doesn't compile unless next line is uncommented
// object: { def foo: Int }
}
This is counter-intuitive. A solution attempt would be to automatically place such constraint on the companion object (in sub-classes and in current class) if the current companion object (of the class which uses object.<something>) has satisfying definition of <something>.
Anyway, "use companion method" is a fitting name of the thread :-) I suspect Francois it is not a coincidence.
What are other possible implementations?
With regards,
Jan
On 16.02.2012 18:03, Daniel Spiewak wrote:
FeWFzagnG878C-DpudQUE1AhpzMMwFNRH7Q [at] mail [dot] gmail [dot] com" type="cite">Of particular concern to me is that (depending on implementation) it seems to provide another type-level mechanism for introducing cycles, giving us a second path to Turing Completeness. I can't find a way to actually exploit the cycle without relying on the "path dependent types of a path dependent type" trick (which is to say, the primary mechanism for fixpoint), but intuitively it feels like this should be possible. My original email on this thread was going to include a proof-of-concept showing how to do this, but I couldn't quite get it to work.
So in other words, I really like the idea of this feature (companion references) in practice, but I think Martin's concerns about extending the type system are very relevant here.
Daniel
On Thu, Feb 16, 2012 at 2:28 AM, martin odersky <martin [dot] odersky [at] epfl [dot] ch" rel="nofollow">martin.odersky@epfl.ch> wrote:
I agree it's useful. But it will also add one or two things to the
type system. And the bar is extremely high for that. Generally, I
would much prefer making the type system simpler than adding stuff to
it.
Cheers
-- Martin
Fri, 2012-02-17, 02:01
#22
Re: Expressing "use companion method" in a hierarchy ?
Hi Jan,
I doubt if that is possible in Scala macros (or Nemerle macros) but it
is an interesting feature.
I think it is made for a one time expand and compile. It is not
possible to trigger that from a second compilation again. So it works
only if the trait with the macro annotation and class are compiled
together.
Otherwise every class must be annotated but that doesn't look nice.
On 16 feb, 20:24, Jan Vanek wrote:
> Hi Dave, I need to read about scala macros yet. What I'm trying to
> understand is how would this work if you compile such trait/class
> separately, without knowing the final class and its companion. How would
> the typing be done or postponed and how would you handle the case where
> the trait/class is extended by 2 classes whose companions provide
> incompatible methods.
>
> Regards,
> Jan
>
> On 16.02.2012 19:09, Dave wrote:
>
>
>
> > For the user
>
> > instead of
> > trait Item { def key : ItemKey = ??companion??.key }
>
> > it is something like:
>
> > trait Item { def key : ItemKey = @Companion key }
>
> > Doesn't look more difficult.
>
> > and macro annotation @Companion is predefined in the scala library so
> > the user doesn't have to implement that.
> > It takes the name of the current class (which is the same as the
> > companion object) and it takes the argument of the macro annotation
> > and creates the method to the companion object in the current class.
>
> > On 16 feb, 17:56, Ittay Dror wrote:
> >> ----
> >> (Sent from my android)
> >> On 16 בפבר 2012 15:10, "Dave" wrote:
>
> >>> If the compiler has a notion about the link between a class and its
> >>> companion object and reducing boiler plate code is the goal then it
> >>> sounds to me like a perfect use case for scala macros, but maybe
> >>> Eugene can comment on that.
> >> I don't agree with this. It is such a useful thing that everyone will need
> >> to know how to use it. Then it is no different than making it part of the
> >> language, but less easy to use and maybe harder to develop. Since the
> >> information is already in the compiler it doesn't sound like there's
> >> something to gain in modularity either.
>
> >>> On 13 feb, 16:52, Paul Phillips wrote:
> >>>> [Moved from scala-user.]
> >>>> I run into this all the time and I don't know how to deal with it
> >> without
> >>>> language support.
> >>>> Internally, the compiler has a very strong, specific, articulated idea
> >> of
> >>>> the link between a class and its companion object. We should expose
> >> that
> >>>> link.
> >>>> Right now there is no way to express, given some unknown T, "the type of
> >>>> T's companion." It would be VERY USEFUL if there was! One can use
> >>>> reflection to acquire the companion instance, but that is a far cry
> >> from a
> >>>> static compiler-enforced relationship. It would be even more useful if
> >> one
> >>>> could also make reference to the types of all the companions of one's
> >>>> parents (the "inherited companions".)
> >>>> I can imagine using manifests for this, so that if one wanted to
> >>>> call companion.method, a manifest would be required which assured that
> >> the
> >>>> companion had such a method. (How to arrange dispatch so that one could
> >>>> generically call methods in the inherited companions I don't know
> >> offhand.)
> >>>> But I'm infinitely flexible on the technique, it's the result I'm after.
> >>>> On Mon, Feb 13, 2012 at 7:03 AM, Francois wrote:
> >>>>> Hello guys,
> >>>>> I have a problem where I have a bunch of case classes used to classify
> >>>>> items.
> >>>>> Items have a key type statically defined on their companion object, so
> >>>>> that they look like:
> >>>>> ======================
> >>>>> trait ItemKey
> >>>>> trait Item { def key : ItemKey }
> >>>>> object A { def key = keyX }
> >>>>> case class A { def key = A.key }
> >>>>> object B { def key = keyY }
> >>>>> case class B { def key = B.key }
> >>>>> ======================
> >>>>> etc
> >>>>> That leads to a bunch of code boilerplate (even more than in that
> >>>>> simplified example), that in turns lead to silly errors (copy past
> >> with the
> >>>>> bad object name, special case where the key is not in the companion
> >> are
> >>>>> hidden in the mass, etc).
> >>>>> I really would be able to express in the Item trait "use the method
> >> 'key'
> >>>>> defined in the companion object of that class".
> >>>>> =========
> >>>>> trait Item { def key : ItemKey = ??companion??.key }
> >>>>> =========
> >>>>> Is this possible ? If not, is there a classical solution to that ?
> >>>>> Having a common trait for both object A and its companion does not
> >> seems
> >>>>> better, as it tends to add even more boilerplate (for case
> >> class/object
> >>>>> pair, we have a third trait to define (ok, with two methods less),
> >> but as
> >>>>> said before, we have dozens of these pairs, with multiple keys to
> >> define
> >>>>> and so with multiple common trait, so a cheaper (in line of code)
> >> solution
> >>>>> would be great !)
> >>>>> Thanks,
> >>>>> --
> >>>>> Francois ARMANDhttp://fanf42.blogspot.comhttp://www.normation.com-
> >> Tekst uit oorspronkelijk bericht niet weergeven -
>
> >>>> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
> >> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>
> >> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Sat, 2012-02-18, 15:21
#23
Re: Expressing "use companion method" in a hierarchy ?
I tried to explore how to access the companion for a type T, both on
syntactical and implementation level, to find one solution for
myself. Before I continue let me say that I see now, that it indeed
needs one or two things to add to the type system, as Mr. Odersky,
ehm, eM ehm, Mr. Odersky, says :-) It's a thought experiment, but it
has a certain appeal so I want to share it.
Let's say we have a trait SomeAble in which we place a constraint on the companion object like this:
trait SomeAble {
object <: CanStartSomething
}
trait CanStartSomething {
def startSomething(v: AnyRef) = ...
}
Then whenever we have a method with a type parameter T which is a subtype of type SomeAble, e.g:
class X {
def someTo[T <: SomeAble] = {
// then we/compiler know that the companion object of type T conforms to CanStartSomething
// and we can call e.g. startSomething(this) on it
}
}
Since at runtime the companion of T is reachable from the runtime class of T, which is erased, we need an "implicit" help from the compiler. I thought about companion method in ClassManifest[T] but although it is possible to get the companion instance from it, I couldn't figure out how to obtain the right companion type from it.
If we get back to trait SomeAble, the declaration object <: CanStartSomething would (one possibility) generate an abstract type and an abstract method:
trait SomeAble {
object <: CanStartSomething // produces:
type Companion <: CanStartSomething
def companion: CanStartSomething
}
So it is possible to imagine the companion object itself being passed as an implicit parameter like this (attempt 1):
class X {
def someTo[T <: SomeAble](implicit T_companion: T#Companion) = {
T_companion.startSomething(this)
}
}
This syntax is a bit clumsy, so another one, which would desugar to it, is needed (attempt 2):
class X {
def someTo[T <: SomeAble : object] = {
T.startSomething(this)
}
}
Here we say to the compiler that we need the companion object of the type T being passed so that we can see symbol T directly as the companion object of type T, analogously to "class A, object A" for regular classes.
OK, that's it, in the following I was trying to use this mechanism and compare it with the famous CanBuildFrom in the collection library.
((here the bells from Daniel's path dependent type of path dependent type ring... but I'm in a fog))
Here is the gist:
https://gist.github.com/1859416
It uses concepts from the collection library, like Builder and Factory and is very rudimentary. When comparing the crucial line:
// def mapTo[B, That[TF] <: Buildable[TF, That] : object](f: T => B): That[B] = {
def mapTo[B, That[TF] <: Buildable[TF, That]](f: T => B)(implicit That: That[B]#Companion): That[B] = {
to e.g. the (in Vector):
def mapFast[B, That](f: A => B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = {
The first one only allows to mapTo something which is Buildable (from which the constraints on the companion are derived, and the companion itself is used to start the building), whereas the second one is clearly more flexible, one can map to anything as long as the builder is provided. In the first one the builder is sort of constrained from the inside, in the second one the builder sort of arrives from outside. The first one makes it little more explicit for the price of limited flexibility.
I have to stop here, I hope you'll enjoy it as much as I did,
Jan
On 16.02.2012 18:03, Daniel Spiewak wrote:
Let's say we have a trait SomeAble in which we place a constraint on the companion object like this:
trait SomeAble {
object <: CanStartSomething
}
trait CanStartSomething {
def startSomething(v: AnyRef) = ...
}
Then whenever we have a method with a type parameter T which is a subtype of type SomeAble, e.g:
class X {
def someTo[T <: SomeAble] = {
// then we/compiler know that the companion object of type T conforms to CanStartSomething
// and we can call e.g. startSomething(this) on it
}
}
Since at runtime the companion of T is reachable from the runtime class of T, which is erased, we need an "implicit" help from the compiler. I thought about companion method in ClassManifest[T] but although it is possible to get the companion instance from it, I couldn't figure out how to obtain the right companion type from it.
If we get back to trait SomeAble, the declaration object <: CanStartSomething would (one possibility) generate an abstract type and an abstract method:
trait SomeAble {
object <: CanStartSomething // produces:
type Companion <: CanStartSomething
def companion: CanStartSomething
}
So it is possible to imagine the companion object itself being passed as an implicit parameter like this (attempt 1):
class X {
def someTo[T <: SomeAble](implicit T_companion: T#Companion) = {
T_companion.startSomething(this)
}
}
This syntax is a bit clumsy, so another one, which would desugar to it, is needed (attempt 2):
class X {
def someTo[T <: SomeAble : object] = {
T.startSomething(this)
}
}
Here we say to the compiler that we need the companion object of the type T being passed so that we can see symbol T directly as the companion object of type T, analogously to "class A, object A" for regular classes.
OK, that's it, in the following I was trying to use this mechanism and compare it with the famous CanBuildFrom in the collection library.
((here the bells from Daniel's path dependent type of path dependent type ring... but I'm in a fog))
Here is the gist:
https://gist.github.com/1859416
It uses concepts from the collection library, like Builder and Factory and is very rudimentary. When comparing the crucial line:
// def mapTo[B, That[TF] <: Buildable[TF, That] : object](f: T => B): That[B] = {
def mapTo[B, That[TF] <: Buildable[TF, That]](f: T => B)(implicit That: That[B]#Companion): That[B] = {
to e.g. the (in Vector):
def mapFast[B, That](f: A => B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = {
The first one only allows to mapTo something which is Buildable (from which the constraints on the companion are derived, and the companion itself is used to start the building), whereas the second one is clearly more flexible, one can map to anything as long as the builder is provided. In the first one the builder is sort of constrained from the inside, in the second one the builder sort of arrives from outside. The first one makes it little more explicit for the price of limited flexibility.
I have to stop here, I hope you'll enjoy it as much as I did,
Jan
On 16.02.2012 18:03, Daniel Spiewak wrote:
FeWFzagnG878C-DpudQUE1AhpzMMwFNRH7Q [at] mail [dot] gmail [dot] com" type="cite">Of particular concern to me is that (depending on implementation) it seems to provide another type-level mechanism for introducing cycles, giving us a second path to Turing Completeness. I can't find a way to actually exploit the cycle without relying on the "path dependent types of a path dependent type" trick (which is to say, the primary mechanism for fixpoint), but intuitively it feels like this should be possible. My original email on this thread was going to include a proof-of-concept showing how to do this, but I couldn't quite get it to work.
So in other words, I really like the idea of this feature (companion references) in practice, but I think Martin's concerns about extending the type system are very relevant here.
Daniel
On Thu, Feb 16, 2012 at 2:28 AM, martin odersky <martin [dot] odersky [at] epfl [dot] ch" rel="nofollow">martin.odersky@epfl.ch> wrote:
I agree it's useful. But it will also add one or two things to the
type system. And the bar is extremely high for that. Generally, I
would much prefer making the type system simpler than adding stuff to
it.
Cheers
-- Martin
Sat, 2012-02-18, 19:51
#24
Re: Expressing "use companion method" in a hierarchy ?
> The object conflates its definition/class and its slot/instance. I
> don't know how but it might be good to separate them, provide means
> for defining "object/companion" slots, and use current class/trait
> semantics for the definition + syntactic sugar. It might be
> conceptually simpler.
>
> This is just too early and might be very wrong.
To close this one I thought about it but if I see the object declaration
as mainly its slot/instance + some optional anonymous piece of code then
saying "object A" is the most concise syntax for defining object slot
which can possibly exist. Also, it makes much sense that the companion
object of class A is defined aside from it, not inside of it. So I was
very wrong, it is perfect.
Jan
I run into this all the time and I don't know how to deal with it without language support.
Internally, the compiler has a very strong, specific, articulated idea of the link between a class and its companion object. We should expose that link.
Right now there is no way to express, given some unknown T, "the type of T's companion." It would be VERY USEFUL if there was! One can use reflection to acquire the companion instance, but that is a far cry from a static compiler-enforced relationship. It would be even more useful if one could also make reference to the types of all the companions of one's parents (the "inherited companions".)
I can imagine using manifests for this, so that if one wanted to call companion.method, a manifest would be required which assured that the companion had such a method. (How to arrange dispatch so that one could generically call methods in the inherited companions I don't know offhand.) But I'm infinitely flexible on the technique, it's the result I'm after.
On Mon, Feb 13, 2012 at 7:03 AM, Francois <fanf42@gmail.com> wrote: