I just wrote a fairly handy generator for making very simple vanilla case classes. It basically uses the apply method defined in the companion of them to make things pretty simple. I am not sure if something similar is in the library already.
basically you can just type in your specification.
implicit val arbPoint = ArbFunc(Point.apply _)
and then arbitrary points will be provided as needed
If I posted the code here i have feeling it would get severely mangled so I put it in a gist:
http://gist.github.com/440002
I think it is a simpler way to make the generators for case classes where you don't care that much about constraining the members of the case class.
posted to the mailing list, waiting for moderation.
Tuesday, June 15, 2010
Monday, June 14, 2010
Working around Dependent Method Types with Structural Types
Until dependent method types move out of experimental status in the scala compiler (they can be enabled with -Xexperimental) we have been using Structural Typing to work around their absence.
Here's how were doing it:
First, Given:
and an implementation:
We would like to write a function with given any AToB
returns the type of B specified by that A:
if we had dependent method types we could write this as
however this gives the error:
To work around this however and still preserve type safety we have been doing this:
Basically we are using a structural type to fix the abstract type B in AToB to a concrete
type BB. This will enforce the type constraint that we want. There is one annoyance that remains
however and I haven't figured out a solution for it yet, the compiler is inferring the wrong type
for BB.
gives the compiler error:
yuck, the work around is to say:
Which will compile correctly.
A few more examples which will not compile:
Here's how were doing it:
First, Given:
trait AToB {
type B
def b : B
}
and an implementation:
trait AToInt extends AToB {
final override type B = Int
}
object AToInt {
def apply(x : Int) = new AToInt {
final override val b = x
}
}
We would like to write a function with given any AToB
returns the type of B specified by that A:
if we had dependent method types we could write this as
def bOf[A <: AToB](a : A) : a.B = a.b
however this gives the error:
error: illegal dependent method type
def bOf[A <: AToB](a : A) : a.B = a.b
To work around this however and still preserve type safety we have been doing this:
def bOf[AA <: AToB {type B = BB}, BB](a : AA) : BB = a.b
Basically we are using a structural type to fix the abstract type B in AToB to a concrete
type BB. This will enforce the type constraint that we want. There is one annoyance that remains
however and I haven't figured out a solution for it yet, the compiler is inferring the wrong type
for BB.
val x : Int = bOf(AToInt(5))
gives the compiler error:
error: inferred type arguments [java.lang.Object with AToInt,Nothing] do not conform to method bOf's type parameter bounds [AA <: AToB{type B = BB},BB]
yuck, the work around is to say:
val x : Int = bOf[AToInt, AToInt#B](AToInt(5))
Which will compile correctly.
A few more examples which will not compile:
trait AToString extends AToB {
final override type B = String
}
object AToString {
def apply(x : String) = new AToString {
final override val b = x
}
}
//Will not compile
val x : String = bOf[AToInt, AToInt#B](AToInt(5))
//Will compile
val x : String = bOf[AToString, AToString#B](AToString("Good Times"))
//Will not compile
val x : Int = bOf[AToString, AToString#B](AToString("Good Times"))
Wednesday, February 3, 2010
Pot of coffee gone, Intellij + Scala + sbt + bash-support plugin = Continuous Unit Testing In The IDE
Got it working, sweet, no more neck strain looking back and forth from the terminal on every error, just their just a quick press away, don't even have to move the mouse and Intellij uses next occurrence to traverse between stacktrace elements in the active console.
Here's the patch for sbt it anyone is interested.
http://gist.github.com/293488
bedtime...
(previous post: http://scalide.blogspot.com/2010/02/trying-to-get-sbt-to-run-in-intellij.html)
(bash-support plugin for intellij http://plugins.intellij.net/plugin/?id=4230)
(mailing list posting http://groups.google.com/group/simple-build-tool/browse_thread/thread/a0cdaccc76c2384a)
Here's the patch for sbt it anyone is interested.
http://gist.github.com/293488
bedtime...
(previous post: http://scalide.blogspot.com/2010/02/trying-to-get-sbt-to-run-in-intellij.html)
(bash-support plugin for intellij http://plugins.intellij.net/plugin/?id=4230)
(mailing list posting http://groups.google.com/group/simple-build-tool/browse_thread/thread/a0cdaccc76c2384a)
Tuesday, February 2, 2010
Trying to get sbt to run in intellij with navigable errors and continuous compiles.
So close, time to brew another pot of coffee, roll up my sleeves, and get to hacking!
http://groups.google.com/group/simple-build-tool/browse_thread/thread/a0cdaccc76c2384a
The dream of a 95% of the way there realtime compilation / unit test runner for scala in intellij is soooo close!
http://groups.google.com/group/simple-build-tool/browse_thread/thread/a0cdaccc76c2384a
The dream of a 95% of the way there realtime compilation / unit test runner for scala in intellij is soooo close!
Wednesday, January 20, 2010
A Better Scala Enumeration Type
I am going to post a link to the Enum type that I wrote due to the limitations of the builtin Scala Version. I don't use the built in enumeration type anymore as I find it very limiting.
(source & test / example):
http://gist.github.com/282446
Originally I wrote this as answer to this question on StackOverflow, however felt that it would be useful here too.
(source & test / example):
http://gist.github.com/282446
Originally I wrote this as answer to this question on StackOverflow, however felt that it would be useful here too.
Tuesday, January 5, 2010
Follow up to Product.hashCode collisions
After some experimentation here is the result that I came up. Note that you might need to increase the Heap Space to get it to run in the interpreter because of sort / removeDuplicates.
I posted it as a gist [http://gist.github.com/270117]
You should be able to just copy and paste it into a scala 2.8 interpreter
This yields a result of:
(ideal = 1000000.0, actual = 999880, uniqueRatio = 0.99988)
meaning a collision rate < .1%
I posted it as a gist [http://gist.github.com/270117]
You should be able to just copy and paste it into a scala 2.8 interpreter
This yields a result of:
(ideal = 1000000.0, actual = 999880, uniqueRatio = 0.99988)
meaning a collision rate < .1%
Possible Collision Issue with Product.hashCode
First Off I am no expert at hashing algo's & perhaps this is some sort of Birthday Problem so I am not sure if what I am pointing out is actually a big issue. It would be interesting to see what would happen on a project that uses large hash maps with Products in it if the distribution at the bottom was improved.
Quick Summary:
Right now it seems like the hashCode for Products of Arity N is the same regardless of the actual class implementing it & that it doesn't distribute very well:
In a little more depth: I think this behavior is much better than in 2.7.5 where the ordering of the product elements did not affect the hashCode. (Point(x,y) would clash with Point(y,x))
in 2.7.5:
Digging a little further on what this means for a distribution =>
Keep in mind that a big problem is that java's Integer.hashCode == the number being hashed, which is going to cause problems.
Using this code to get rudimentary collision distribution:
Here is the 2.7.5 result (takes a few minutes on a Core i7 920, removeDuplicates is terribly slow):
and Here is the 2.8 nightly result (surprisingly the same distribution, that takes only a few seconds):
Both cases are going to collide 90+% of the time (notice that changing tot to 100 reduces the collision % quite significantly so I suspect there is a quadratic relationship at play here)
Running with a tot =100 gives:
Still a 58% collide rate, but a lot better than the larger case.
Finally for the 3 Tuple cases with tot = 100
Perhaps I should look into a better case than just integers to see what the collision rates actually are like.
Quick Summary:
Right now it seems like the hashCode for Products of Arity N is the same regardless of the actual class implementing it & that it doesn't distribute very well:
case class Point(x : Int, y : Int)
case class Point2(x : Int, y : Int)
(1,2).hashCode == Point(1,2).hashCode == Point2(1,2).hashCode == 3405
Welcome to Scala version 2.8.0.r20331-b20100101020206 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
List((1,2), (2,1), Point(1,2), Point(2,1), Point2(1,2), Point2(2,1)).map(_.hashCode)
res0: List[Int] = List(3405, 3445, 3405, 3445, 3405, 3445)
In a little more depth: I think this behavior is much better than in 2.7.5 where the ordering of the product elements did not affect the hashCode. (Point(x,y) would clash with Point(y,x))
in 2.7.5:
res0: List[Int] = List(1838716253, 1838716293, -1163646902, -1163646862, -270917823, -270917783)
Digging a little further on what this means for a distribution =>
Keep in mind that a big problem is that java's Integer.hashCode == the number being hashed, which is going to cause problems.
Using this code to get rudimentary collision distribution:
val tot = 500
val ideal = tot * tot * 1.0
val hashes = (for(x <- -(tot/2) until (tot/2); y <- -(tot/2) until (tot/2)) yield (x,y).hashCode ).toList
val hset = Set() ++ hashes
val hsSize = hset.size
val hlSize = hashes.removeDuplicates.size
println((ideal, hsSize, hsSize/ideal, hlSize, hlSize/ideal))
Here is the 2.7.5 result (takes a few minutes on a Core i7 920, removeDuplicates is terribly slow):
(250000.0, 20959,0.083836,20959,0.083836)
and Here is the 2.8 nightly result (surprisingly the same distribution, that takes only a few seconds):
(250000.0, 20959,0.083836,20959,0.083836)
Both cases are going to collide 90+% of the time (notice that changing tot to 100 reduces the collision % quite significantly so I suspect there is a quadratic relationship at play here)
Running with a tot =100 gives:
(10000.0,4159,0.4159,4159,0.4159)
Still a 58% collide rate, but a lot better than the larger case.
Finally for the 3 Tuple cases with tot = 100
(1000000.0,170578,0.170578,170578,0.170578)
Perhaps I should look into a better case than just integers to see what the collision rates actually are like.
Subscribe to:
Posts (Atom)