How to correctly implement a custom number-like class in Scala? - scala

I am currently trying to implement my own UnsignedInt. I would like to implement this correctly so that it fits into the whole Scala type & class system. However, I am really confused by all the classes that fit into Number.
With which class(es) do I need to work: Numeric, Integral or ScalaNumber? Or something completely different? What classes and/or traits should my own class implement?

The short answer is: don't implement your own, use the Spire one :) Otherwise, you should implement Integral (which includes Numeric). Note that your type shouldn't extend it; you need implicit values in the companion object, i.e.
class UnsignedInt { ... }
object UnsignedInt {
implicit val UIntIntegral: Integral[UnsignedInt] = ...
}
You should also consider making your class a value class.

Related

Is there a difference between extending a trait with a type or using a type parameter in your case class?

I recently had a coworker implement a trait like
trait CaseClassStuff{
type T
val value: T
}
and then used it to instantiate case classes as
case class MyCaseClassString(value: String) extends CaseClassStuff { type T = String }
case class MyCaseClassDouble(value: Double) extends CaseClassStuff { type T = Double }
and I thought that was particularly whacky since it seemed reasonable enough to just do
case class MyCaseClass[T](value: T)
to get the exact same result. There was argument over how using the trait allowed us to avoid needing to update anything using that case class, since with the trait we just explicitly used MyCaseClassString and MyCaseClassDouble in different areas, but I wasn't sure how since they seemed to be ostensibly the same thing, especially since the only change between the two is their type. The program using them was set up to parse out the logic when it was a double or a string received.
So, my question is about whether or not they are different as far as the compiler is concerned, and whether or not there is actual benefit from doing it the way with the trait in general, or if it was just specific to my situation. It wasn't clear to either of us if it was best practice to use the trait or just the type parameter, since it seems like two ways to accomplish the same outcome.

Is there a way to make sure that a class overrides hashCode

I am creating a cache, and want to make sure that the key type overrides hashCode.
If hashCode was not already defined on Object, something like this would work
trait Key {
def hashCode: Int
}
If the keys are always case classes it is obviously not a problem, but I want to make sure that if somebody passes a regular class it will fail. Is there a way to do it in Scala?
On a side note: My key is specifications for a SQL query which currently is represented as case classes. For example
case class Filter(age: Option[Int], gender: Option[String])
But eventually, I want to represent it using a cleaner specification pattern implementation (for example: https://gist.github.com/lbialy/912fad3c909374b81ce7)
If you want to explicitly whitelist classes that are allowed to use their hashCode, you cannot use inheritance for that, but you can provide your own typeclass:
trait HasApprovedHashCode[X] {
def hashCode(x: X): Int
}
and then modify all the methods that crucially rely on a proper implementation of hashCode like this:
def methodRelyingOnHashCode[K: HasApprovedHashCode, V](...) = ...
Now you can explicitly whitelist only those classes that you deem as having good enough implementation of hashCode.
Usually, I would say: hash code of the used key is not your responsibility. If the user of your library insists on shooting h(im/er)self in the foot, you cannot prevent it. You shouldn't facilitate it, or even create a situation where this is almost inevitable, but it's not your responsibility to hunt down every single class out there that could somehow misbehave when used as a key of a map.

scala: inheriting base class from type parameter

Is that possible to create a type class based on type parameter by inheriting type parameter like in the code below?
I do suspect that this is fundamentally not possible as this is a scala limitation as functional language...
But if possible what I have to change in the code below??
class MyInt[T : Numeric] extends T {
}
It's not possible. You can extend a class (traits included), but you cannot extend a type, and T is a type.
Even if it were possible, what would it then mean to have MyInt[Int] (which is final), or MyInt[List[String]] (which is not a class) ? It would get quite complicated for the compiler very quickly.

Scala type alias with companion object

I'm a relatively new Scala user and I wanted to get an opinion on the current design of my code.
I have a few classes that are all represented as fixed length Vector[Byte] (ultimately they are used in a learning algorithm that requires a byte string), say A, B and C.
I would like these classes to be referred to as A, B and C elsewhere in the package for readability sake and I don't need to add any extra class methods to Vector for these methods. Hence, I don't think the extend-my-library pattern is useful here.
However, I would like to include all the useful functional methods that come with Vector without having to 'drill' into a wrapper object each time. As efficiency is important here, I also didn't want the added weight of a wrapper.
Therefore I decided to define type aliases in the package object:
package object abc {
type A: Vector[Byte]
type B: Vector[Byte]
type C: Vector[Byte]
}
However, each has it's own fixed length and I would like to include factory methods for their creation. It seems like this is what companion objects are for. This is how my final design looks:
package object abc {
type A: Vector[Byte]
object A {
val LENGTH: Int = ...
def apply(...): A = {
Vector.tabulate...
}
}
...
}
Everything compiles and it allows me to do stuff like this:
val a: A = A(...)
a map {...} mkString(...)
I can't find anything specifically warning against writing companion objects for type aliases, but it seems it goes against how type aliases should be used. It also means that all three of these classes are defined in the same file, when ideally they should be separated.
Are there any hidden problems with this approach?
Is there a better design for this problem?
Thanks.
I guess it is totally ok, because you are not really implementing a companion object.
If you were, you would have access to private fields of immutable.Vector from inside object A (like e.g. private var dirty), which you do not have.
Thus, although it somewhat feels like A is a companion object, it really isn't.
If it were possible to create a companion object for any type by using type alias would make member visibility constraints moot (except maybe for private|protected[this]).
Furthermore, naming the object like the type alias clarifies context and purpose of the object, which is a plus in my book.
Having them all in one file is something that is pretty common in scala as I know it (e.g. when using the type class pattern).
Thus:
No pitfalls, I know of.
And, imho, no need for a different approach.

Scala: Do classes that extend a trait always take the traits properties?

Given the following:
class TestClass extends TestTrait {
def doesSomething() = methodValue + intValue
}
trait TestTrait {
val intValue = 4
val unusedValue = 5
def methodValue = "method"
def unusedMethod = "unused method"
}
When the above code runs, will TestClass actually have memory allocated to unusedValue or unusedMethod? I've used javap and I know that there exists an unusedValue and an unusedMethod, but I cannot determine if they are actually populated with any sort of state or memory allocation.
Basically, I'm trying to understand if a class ALWAYS gets all that a trait provides, or if the compiler is smart enough to only provide what the class actually uses from the trait?
If a trait always imposes itself on a class, it seems like it could be inefficient, since I expect many programmers will use traits as mixins and therefore wasting memory everywhere.
Thanks to all who read and help me get to the bottom of this!
Generally speaking, in languages like Scala and Java and C++, each class has a table of pointers to its instance methods. If your question is whether the Scala compiler will allocate slots in the method table for unusedMethod then I would say yes it should.
I think your question is whether the Scala compiler will look at the body of TestClass and say "whoa, I only see uses of methodValue and intValue, so being a good compiler I'm going to refrain from allocating space in TestClass's method table for unusedMethod. But it can't really do this in general. The reason is, TestClass will be compiled into a class file TestClass.class and this class may be used in a library by programmers that you don't even know.
And what will they want to do with your class? This:
var x = new TestClass();
print(x.unusedMethod)
See, the thing is the compiler can't predict who is going to use this class in the future, so it puts all methods into its method table, even the ones not called by other methods in the class. This applies to methods declared in the class or picked up via an implemented trait.
If you expect the compiler to do global system-wide static analysis and optimization over a fixed, closed system then I suppose in theory it could whittle away such things, but I suspect that would be a very expensive optimization and not really worth it. If you need this kind of memory savings you would be better off writing smaller traits on your own. :)
It may be easiest to think about how Scala implements traits at the JVM level:
An interface is generated with the same name as the trait, containing all the trait's method signatures
If the trait contains only abstract methods, then nothing more is needed
If the trait contains any concrete methods, then the definition of these will be copied into any class that mixes in the trait
Any vals/vars will also get copied verbatim
It's also worth noting how a hypothetical var bippy: Int is implemented in equivalent java:
private int bippy; //backing field
public int bippy() { return this.bippy; } //getter
public void bippy_$eq(int x) { this.bippy = x; } //setter
For a val, the backing field is final and no setter is generated
When mixing-in a trait, the compiler doesn't analyse usage. For one thing, this would break the contract made by the interface. It would also take an unacceptably long time to perform such an analysis. This means that you will always inherit the cost of the backing fields from any vals/vars that get mixed in.
As you already hinted, if this is a problem then the solution is just use defs in your traits.
There are several other benefits to such an approach and, thanks to the uniform access principle, you can always override such a method with a val further down in the inheritance hierarchy if you need to.