Extending Option w/reason - scala

I would like to be able to pass an optional reason for a "None". I tried just extending 'None' ex:
case class NoneReason(reason: String) extends None
but get a "not found: type None", then I tried:
case class NoneReason(reason: String) extends Option[Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("None.get")
}
but I get a ""illegal inheritance from sealed class Option"
I'm guessing this is a special case because 'None' is actually an alias for null or something.
I considered copying the Option source and renaming it to TriOption or something, but this seems gross to maintain. What would be an elegant way to get around this?

An optional reason for None is an Either[Option[String], Foo], where Foo is your type. You can't extend None; it's a singleton, so you can consider it to be a value like null.
But the Either class is made to select between two alternatives, with the right branch by convention containing a "correct" answer (if one is more correct than the other). If you want an optional error message, that goes in the left branch. Thus, you can switch to the type shown above and then wherever you would normally use Option you can x.right.toOption to convert to an option without a message, or use pattern matching or whatever, e.g.
x match {
case Right(foo) => useFoo(foo)
case Left(None) => throw new Exception("Something went wrong.")
case Left(Some(msg)) => throw new Exception(msg + " went wrong.")
}
If you find this to have too much boilerplate, you could use ScalaUtils or Scalaz or any of a number of other libraries that have an Option-with-reason alternative. ScalaUtils is really easy to get up to speed with. Scalaz is much deeper, which if you need the depth is awesome and if you don't means that it takes longer to start being productive.

None is not alias to null. it is an object (singleton) which extends Option[Nothing].
The reason you cannot extend it is that Option is sealed class, which mean it can be extends only by classes in the same file as the sealed class.
The way to go is, as Lee wrote in the comment to your question, is to use Try[T] or Either[String, T].
Here some nice explanation of how to use them.

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.

How to copy a case class and add a mixin?

I'd like to have a base case class I can extend at will into different types. I had something like this working previously, but I must have screwed something up, because now I'm getting compile errors.
trait JobLike
case class Task(name: String) {
def as[T <: JobLike]: Task with T = new Task(this.name) with T
}
The problem is, this gives me a compiler error like this:
java.lang.UnsupportedOperationException: addChild inapplicable for type T
at scala.reflect.internal.Symbols$Symbol.addChild(Symbols.scala:1835)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$templateSig$1(Namers.scala:1119)
at scala.tools.nsc.typechecker.Namers$Namer.templateSig(Namers.scala:1107)
at scala.tools.nsc.typechecker.Namers$Namer.classSig(Namers.scala:1178)
at scala.tools.nsc.typechecker.Namers$Namer.memberSig(Namers.scala:1788)
at scala.tools.nsc.typechecker.Namers$Namer.typeSig(Namers.scala:1751)
at scala.tools.nsc.typechecker.Namers$Namer$MonoTypeCompleter.completeImpl(Namers.scala:836)
...
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:82)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:85)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)</code>
I swear, I had something working yesterday that basically did just this, but now it's throwing this error.
You managed to hit a compiler bug! While that's certainly an issue, and should be reported, the thing is that your code isn't possible anyway, and it's better that it's crashing and bringing you here than "working" and doing something horribly wrong. Because T can be any subtype of JobLike, there's simply no way to mix it in at compile time. I could very well do trait Boom extends JobLike { def something: Int }; task.as[Boom], and then task couldn't create a Boom because there's no implementation for something.
You can provide asJobLike: Task with JobLike instead of a general as[T]: Task with T, which is completely possible. (Note that it's discouraged to make subtypes of case classes, so you may want to create a new class. The reason is that it breaks the reflexivity of equals.)
Something rather filthy that you can do is call (new Task(this.name) with JobLike).asInstanceOf[Task with T]. asInstanceOf only checks the cast for the leftmost type in the with, so this will not ClassCastException off the bat (you can also do "a".asInstanceOf[String with Int].). It will generally sorta work (modulus asInstanceOf[T] being false) as long as T has no members.
Something horrible that you can also do is use runtime reflection to dynamically create the required class. The trick as a whole is filthy and completely unsafe, so I won't say it here, but have a link.

Case object extending class with constructor in Scala

I am a beginner in Scala and was playing around to learn more about Abstract data types. I defined the following definition to replicate Option type:
sealed abstract class Maybe[+A](x:A)
case object Nothing extends Maybe[Nothing](Nothing)
case class Just[A](x:A) extends Maybe[A](x)
But I encountered the following error.
found : Nothing.type
required: Nothing
case object Nothing extends Maybe[Nothing](Nothing)
How do I pass Nothing instead of Nothing.type?
I referred to the following question for hints:
How to extend an object in Scala with an abstract class with constructor?, but it was not helpful.
Maybe more like this. Your Nothing shouldnt have a value, just the type. Also people usually use traits instead of abstract classes.
sealed trait Maybe[+A]
case object None extends Maybe[Nothing]
case class Just[A](x:A) extends Maybe[A]
You probably shouldnt create your own Nothing, thats going to be confusing, you will confuse yourself and the compiler about if you are referring to your one, or the one at the bottom of the type hierarchy.
As mentioned by Stephen, the correct way to do this would be not to have trait and not an abstract class, however, I thought it might be informative to explain why the current methodology fails and how to fix it.
The main issue is with this line:
case object Nothing extends Maybe[Nothing](Nothing)
First thing (as mentioned) you shouldn't call your object Nothing. Secondly, you set the object to extend Maybe[Nothing]. Nothing can't have any actual values so you can't use it as an object. Also, you can't use the object itself as the constructor parameter because that would cause a cyclic behavior.
What you need is to have a bottom type (i.e. a type which all A have in common) and an object of that type. Nothing is a bottom type but has no objects.
A possible solution is to limit yourself to AnyRef (i.e. nullable objects) and use the Null bottom type which has a valid object (null):
sealed abstract class Maybe[+A <: AnyRef](x:A)
case object None extends Maybe[Null](null)
This is a bit of clarification for Assaf Mendelson's answer, but it's too big for a comment.
case object Nothing extends Maybe[Nothing](Nothing)
Scala has separate namespaces for types and values. Nothing in case object Nothing is a value. Nothing in Maybe[Nothing] is a type. Since you didn't define a type called Nothing, it refers to the automatically imported scala.Nothing and you must pass a value of this type as an argument. By definition it has no values but e.g. case object Nothing extends Maybe[Nothing](throw new Exception) would compile, as the type of throw expressions is Nothing. Instead you pass the value Nothing, i.e. the same case object you are defining; its type is written as Nothing.type.
How do I pass Nothing instead of Nothing.type?
It seems like there is no way to do so.
As it says at http://www.scala-lang.org/api/2.9.1/scala/Nothing.html:
there exist no instances of this type.

Getting field name and types from Case Class (with Option)

Assuming we have a model of something, represented as a case class, as so
case class User(firstName:String,lastName:String,age:Int,planet:Option[Planet])
sealed abstract class Planet
case object Earth extends Planet
case object Mars extends Planet
case object Venus extends Planet
Essentially, either by use of reflection, or Macros, to be able to get the field names of the User case class, as well as the types represented by the fields. This also includes Option, i.e. in the example provided, need to be able to differentiate between an Option[Planet] and just a Planet
In scala'ish pseudocode, something like this
val someMap = createTypedMap[User] // Assume createTypedMap is some function which returns map of Strings to Types
someMap.foreach{case(fieldName,someType) {
val statement = someType match {
case String => s"$fieldName happened to be a string"
case Int => s"$fieldName happened to be an integer"
case Planet => s"$fieldName happened to be a planet"
case Option[Planet] => s"$fieldName happened to be an optional planet"
case _ => s"unknown type for $fieldName"
}
println(statement)
}
I am currently aware that you can't do stuff like case Option[Planet], since it gets erased by Scala's erasure, however even when using TypeTags, I am unable to wrote code that does what I am trying to do, and possibly deal with other types (like Either[SomeError,String]).
Currently we are using the latest version of Scala (2.11.2) so any solution that uses TypeTags or ClassTags or macros would be more than enough.
Option is a type-parametrized type (Option[T]). At runtime, unless you have structured your code to use type tags, you have no mean to distinguish between an Option[String] and an Option[Int], due to type erasure (this is true for all type-parametrized types).
Nonetheless, you can discriminate between an Option[*] and a Planet. Just keep in mind the first issue.
Through reflection, getting all the "things" inside a class is easy. For example, say you only want the getters (you can put other types of filters, there are A LOT of them, and not all behave as expected when inheritance is part of the process, so you'll need to experiment a little):
import reflect.runtime.{universe=>ru}
val fieldSymbols = ru.typeOf[User].members.collect{
case m: ru.MethodSymbol if m.isGetter => m
}
Another option you'd have, if you are calling the code on instances rather than on classes, is to go through every method, call the method and assign the result to a variable, and then test the type of the variable. This assumes that you are only calling methods that don't alter the state of the instance.
You have a lot of options, time for you to find the best one for your needs.

Using private constructor in a macro

I want to use a private constructor in a macro. This example is a positive integer, but the basic pattern could not only be used for other numeric types like even numbers, but also string derived types like email addresses or a directory name. By making the constructor private the user is denied the opportunity to make an illegal type. I have the following code:
object PosInt
{
import language.experimental.macros
import reflect.runtime.universe._
import reflect.macros.Context
def op(inp: Int): Option[PosInt] = if (inp > 0) Some(new PosInt(inp)) else None
def apply(param: Int): PosInt = macro apply_impl
def apply_impl(c: Context)(param: c.Expr[Int]): c.Expr[PosInt] =
{
import c.universe._
param match {
case Expr(Literal(i)) if (i.value.asInstanceOf[Int] > 0) =>
case Expr(Literal(i)) if (i.value.asInstanceOf[Int] == 0) => c.abort(c.enclosingPosition, "0 is not a positive integer")
case Expr(Literal(i)) => c.abort(c.enclosingPosition, "is not a positive integer")
case _ => c.abort(c.enclosingPosition, "Not a Literal")
}
reify{new PosInt(param.splice)}
}
}
class PosInt (val value: Int) extends AnyVal
However if I make the PosInt Constructor private, although the Macro compiles as expected I get an error if try to use the macro. I can't work out how to build the expression tree manually, but I'm not sure if that would help anyway. Is there anyway I can do this?
You still can't use a private constructor even if PosInt is not a value class. I'll accept an answer that doesn't use a value class. The disadvantage of value classes is that they get type erasure. Plus classes that I'm interested in like subsets of 2d co-ordinates can't be implement as value classes anyway. I'm not actually interested in Positive Integers, I'm just using them as a simple test bed. I'm using Scala 2.11M5. Scala 2.11 will have the addition of the quasiquotes feature. I haven't worked out how to use, quasiquotes yet, as all the material at the moment on them seems to assume a familiarity with Macro Paradise, which I don't have.
Unfortunately for what you are trying to achieve, macros do not work this way. They just manipulate the AST at compile time. Whatever the final result is, it is always something you could have written literally in Scala (without the macro).
Thus, in order to constrain the possible values of PosInt, you will need a runtime check somewhere, either in a public constructor or in a factory method on the companion object.
If runtime exceptions are not palatable to you, then one possible approach would be:
Make the constructor private on the class.
Provide (for example) a create method on the companion object that returns Option[PosInt] (or Try[PosInt], or some other type of your choice that allows you to express a "failure" when the argument is out of range).
Provide an apply method on the companion object similar to your example, which verifies at compile time that the argument is in range and then returns an expression tree that simply calls create(x).get.
Calling .get on the Option is acceptable in this case because you are sure that it will never be None.
The downside is that you have to repeat the check twice: once at compile time, and once at runtime.
I'm not an expert, but I figured I'll give it a shot...
In Java, the scope of a private constructor is limited to the same class... so the PosInt object would need to be moved into the scope of the same class from which it's being called.
With that said, I found an article that shows two ways you can keep the object from being inherited # http://www.developer.com/java/other/article.php/3109251/Stopping-Your-Class-from-Being-Inherited-in-Java-the-Official-Way-and-the-Unofficial-Way.htm
It describes using the "final" keyword in the class declaration to prevent it from being inherited. That's the "official" way. The "unofficial" way is to make the constructor private, but add a public static method that returns an object of the class...
Yes, I know, it is an old question... but it was left unanswered. You never know when an old question will be the top hit in someone's search results...