Quantcast

typedef-like like syntax for strong typing keys

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

typedef-like like syntax for strong typing keys

Josh Stratton
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Rex Kerr-2
type NameKey = Int
type CountryKey = Int
val nameHash = new collection.mutable.HashMap[NameKey,String]()
val name:NameKey = 5
val country:CountryKey = 6
nameHash += (4,"Hi")  // Compiler error
nameHash += (name,"Hello")  // Works
nameHash += (country,"Yo")  // Compiler error

  --Rex


On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Rex Kerr-2
No, actually, that *doesn't* work.  I got confused by not having a fresh shell open.

My mistake.  Those all work.  (And you need ((4,"Hi")) in each case.)

In that case, the shortest thing I know of is making a wrapper class (may as well make it a case class):

case class NameKey(val key:Int) {
  override def hashCode = key
}
case class CountryKey(key:Int) {
  override def hashCode = key
}
val nameHash = new collection.mutable.HashMap[NameKey,String]()
val name = NameKey(5)
val country = CountryKey(5)
nameHash += ((4,"Hi"))  // Error
nameHash += ((name,"Hello"))  // Works
nameHash += ((country,"Yo"))  // Error

If you want easier interoperability with integers for some reason, you can add implicit conversions:

implicit def namekey2int(n:NameKey):Int = n.key
implicit def int2namekey(i:Int):NameKey = NameKey(i)

And keep in mind that you have to box integers in hash maps anyway (at least until @specialized goes all the way through the library), so you don't lose anything by doing your own boxing of the primitive except for a bit of typing.

  --Rex

On Tue, Dec 1, 2009 at 2:02 PM, Rex Kerr <[hidden email]> wrote:
type NameKey = Int
type CountryKey = Int
val nameHash = new collection.mutable.HashMap[NameKey,String]()
val name:NameKey = 5
val country:CountryKey = 6
nameHash += (4,"Hi")  // Compiler error
nameHash += (name,"Hello")  // Works
nameHash += (country,"Yo")  // Compiler error

  --Rex



On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Maxime Lévesque
In reply to this post by Josh Stratton

  I wonder what would be the consequence of allowing to
subclass AnyVal types with the restriction of only extending
with traits without state. We could use it to get a bit more
static validation, like what you're trying to do here, and probably
other interesting uses.
I haven't thought of all consequences and side effects though,
has anyone thought of this ?

  Cheers

On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Maxime Lévesque

  Now that I think of it, even having the restriction of adding traits
without method (to avoid an undesired side effect) would still be usefull ...


2009/12/1 Maxime Lévesque <[hidden email]>

  I wonder what would be the consequence of allowing to
subclass AnyVal types with the restriction of only extending
with traits without state. We could use it to get a bit more
static validation, like what you're trying to do here, and probably
other interesting uses.
I haven't thought of all consequences and side effects though,
has anyone thought of this ?

  Cheers

On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Daniel Sobral
In reply to this post by Maxime Lévesque
It approaches what the unsupported units pluging does, though not as powerful.
 
In that, you could basically define units and have them checked at compile and run-time:
 
val t = 10.0s
val d = 5.0m
val v = d / t
val error = d + t
 
But it seems Josh is thinking of more complex types. It could be done with subclassing:
 
class Complex(val r: Double, val i: Double)
class ComplexTime(_r: Double, _i: Double) extends Complex(_r, _i)
class ComplexDistance(_r: Double, _i: Double) extends Complex(_r, _i)
 
Now, Scala's type aliases are interesting and useful, but it is truly a shame that there isn't a typedef-like facility.

2009/12/1 Maxime Lévesque <[hidden email]>

  I wonder what would be the consequence of allowing to
subclass AnyVal types with the restriction of only extending
with traits without state. We could use it to get a bit more
static validation, like what you're trying to do here, and probably
other interesting uses.
I haven't thought of all consequences and side effects though,
has anyone thought of this ?

  Cheers

On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh




--
Daniel C. Sobral

I travel to the future all the time.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Raoul Duke
> Now, Scala's type aliases are interesting and useful, but it is truly a
> shame that there isn't a typedef-like facility.

understatement :-)
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Maxime Lévesque
In reply to this post by Daniel Sobral

  I'm not familiar with the plugin, but it seems
that allowing extending AnyVals with stateless traits
would give you the same level of static validation while
staying lightweight, would you agree ?

 If I had to pick just one feature, I'd say that value types
(supported by the VM and the language) would give you all this, i.e.
one could make primitive type wrappers (with implicit convs) that would be as
or nearly as lightweight as Primitive types,
but if that is not likely to happen anytime soon, extending
AnyVals sound like a good compromize. Does it ?

 Cheers


2009/12/1 Daniel Sobral <[hidden email]>
It approaches what the unsupported units pluging does, though not as powerful.
 
In that, you could basically define units and have them checked at compile and run-time:
 
val t = 10.0s
val d = 5.0m
val v = d / t
val error = d + t
 
But it seems Josh is thinking of more complex types. It could be done with subclassing:
 
class Complex(val r: Double, val i: Double)
class ComplexTime(_r: Double, _i: Double) extends Complex(_r, _i)
class ComplexDistance(_r: Double, _i: Double) extends Complex(_r, _i)
 
Now, Scala's type aliases are interesting and useful, but it is truly a shame that there isn't a typedef-like facility.

2009/12/1 Maxime Lévesque <[hidden email]>

  I wonder what would be the consequence of allowing to
subclass AnyVal types with the restriction of only extending
with traits without state. We could use it to get a bit more
static validation, like what you're trying to do here, and probably
other interesting uses.
I haven't thought of all consequences and side effects though,
has anyone thought of this ?

  Cheers

On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh




--
Daniel C. Sobral

I travel to the future all the time.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Daniel Sobral
Units is much more powerful. For instance, you can do this with units:
 
val a = v / (t * t)
 
That is, I end up not with distance/time, but with distance/time-squared.
 
There's an implementation of such a thing using Church Numbers, but it is awkward.
 
I think both C# and F# support units nowadays.
2009/12/1 Maxime Lévesque <[hidden email]>

  I'm not familiar with the plugin, but it seems
that allowing extending AnyVals with stateless traits
would give you the same level of static validation while
staying lightweight, would you agree ?

 If I had to pick just one feature, I'd say that value types
(supported by the VM and the language) would give you all this, i.e.
one could make primitive type wrappers (with implicit convs) that would be as
or nearly as lightweight as Primitive types,
but if that is not likely to happen anytime soon, extending
AnyVals sound like a good compromize. Does it ?

 Cheers


2009/12/1 Daniel Sobral <[hidden email]>

It approaches what the unsupported units pluging does, though not as powerful.
 
In that, you could basically define units and have them checked at compile and run-time:
 
val t = 10.0s
val d = 5.0m
val v = d / t
val error = d + t
 
But it seems Josh is thinking of more complex types. It could be done with subclassing:
 
class Complex(val r: Double, val i: Double)
class ComplexTime(_r: Double, _i: Double) extends Complex(_r, _i)
class ComplexDistance(_r: Double, _i: Double) extends Complex(_r, _i)
 
Now, Scala's type aliases are interesting and useful, but it is truly a shame that there isn't a typedef-like facility.

2009/12/1 Maxime Lévesque <[hidden email]>

  I wonder what would be the consequence of allowing to
subclass AnyVal types with the restriction of only extending
with traits without state. We could use it to get a bit more
static validation, like what you're trying to do here, and probably
other interesting uses.
I haven't thought of all consequences and side effects though,
has anyone thought of this ?

  Cheers

On Tue, Dec 1, 2009 at 1:44 PM, Josh Stratton <[hidden email]> wrote:
Is there an equivalent to a typedef in Scala for primitives?  I'm
working with a bunch of different hashes that use integer keys, and
didn't want one key to be used for a different hashmap than intended.
Obviously, it would be the programmer's responsibility not to do that,
but I was wondering if there was a way to make sure it didn't happen
at compile time.

For example,

val nameHash = new HashMap[NameKey,String]()
val countryHash = new HashMap[CountryKey,String]()

...

val country = 5 : CountryKey

and trying to use 'country' as an index in nameHash throws a compiler error?

Josh




--
Daniel C. Sobral

I travel to the future all the time.




--
Daniel C. Sobral

I travel to the future all the time.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: typedef-like like syntax for strong typing keys

Geoff Reedy
In reply to this post by Josh Stratton
On Tue, Dec 01, 2009 at 10:44:50AM -0800, Josh Stratton said
> Is there an equivalent to a typedef in Scala for primitives?  I'm
> working with a bunch of different hashes that use integer keys, and
> didn't want one key to be used for a different hashmap than intended.
> Obviously, it would be the programmer's responsibility not to do that,
> but I was wondering if there was a way to make sure it didn't happen
> at compile time.

It's possible but a little weird.

trait Typedef[T] {
  type Type >: T
  def apply(x: T): Type = x
}

object Types {
 val Name: Typedef[Int] = new Typedef[Int] { type Type = Int }
 val Country: Typedef[Int] = new Typedef[Int] { type Type = Int }
}

import scala.collection.immutable.HashMap
import Types._

val nameHash = new HashMap[Name.Type,String]
val countryHash = new HashMap[Country.Type,String]

val name = 5: Name.Type
val country = 5: Country.Type

In this setup

nameHash.get(5) compiles
nameHash.get(name) compiles
nameHash.get(country) doesn't

countryHash.get(5) compiles
countryHash.get(country) compiles
countryHash.get(name) doesn't

There's no boxing going on as

name isInstanceOf[Int] and country isInstanceOf[Int] are both true

It's also possible to use

Name(5) and Country(5) as equivalents for (5: Name.Type) and (5:
Country.Type) respectively

Of course it still would be nice if scala had something builtin along
the lines of newtype in haskell.

-- Geoff
Loading...