What Is the Point of the Class Option[T]

What is the point of the class Option[T]?

You'll get the point of Option better if you force yourself to never, ever, use get. That's because get is the equivalent of "ok, send me back to null-land".

So, take that example of yours. How would you call display without using get? Here are some alternatives:

getPerson2 foreach (_.display)
for (person <- getPerson2) person.display
getPerson2 match {
case Some(person) => person.display
case _ =>
}
getPerson2.getOrElse(Person("Unknown", 0)).display

None of this alternatives will let you call display on something that does not exist.

As for why get exists, Scala doesn't tell you how your code should be written. It may gently prod you, but if you want to fall back to no safety net, it's your choice.


You nailed it here:

is the only advantage of Option[T] is
that it explicitly tells the
programmer that this method could
return None?

Except for the "only". But let me restate that in another way: the main advantage of Option[T] over T is type safety. It ensures you won't be sending a T method to an object that may not exist, as the compiler won't let you.

You said you have to test for nullability in both cases, but if you forget -- or don't know -- you have to check for null, will the compiler tell you? Or will your users?

Of course, because of its interoperability with Java, Scala allows nulls just as Java does. So if you use Java libraries, if you use badly written Scala libraries, or if you use badly written personal Scala libraries, you'll still have to deal with null pointers.

Other two important advantages of Option I can think of are:

  • Documentation: a method type signature will tell you whether an object is always returned or not.

  • Monadic composability.

The latter one takes much longer to fully appreciate, and it's not well suited to simple examples, as it only shows its strength on complex code. So, I'll give an example below, but I'm well aware it will hardly mean anything except for the people who get it already.

for {
person <- getUsers
email <- person.getEmail // Assuming getEmail returns Option[String]
} yield (person, email)

When to use Option

You should avoid null as much as possible in Scala. It really only exists for interoperability with Java. So, instead of null, use Option whenever it's possible that a function or method can return "no value", or when it's logically valid for a member variable to have "no value".

With regard to your Racer example: Is a Racer really valid if it doesn't have a car, currentRace and team? If not, then you shouldn't make those member variables options. Don't just make them options because it's theoretically possible to assign them to null; do it only if logically you consider it a valid Racer object if any of those member variables has no value.

In other words, it's best to pretend as if null doesn't exist. The use of null in Scala code is a code smell.

def foo(): Option[Result] = if (something) Some(new Result()) else None

Note that Option has many useful methods to work with.

val opt = foo()

// You can use pattern matching
opt match {
case Some(result) => println("The result is: " + result)
case None => println("There was no result!")
}

// Or use for example foreach
opt foreach { result => println("The result is: " + result) }

Also, if you want to program in the functional style, you should avoid mutable data as much as possible, which means: avoid the use of var, use val instead, use immutable collections and make your own classes immutable as much as possible.

Is class parameters with the option type need not to pass a value?

Three lines down, you can see that Table has an auxiliary constructor with two parameters of type Tag and String (note: no Option here):

def this(_tableTag: Tag, _tableName: String) = this(_tableTag, None, _tableName)

This is the constructor that is called in the example code you showed, not the primary constructor.

You can also see the two constructors in the documentation.

What's the point of Guava's Optional class

Guava team member here.

Probably the single biggest disadvantage of null is that it's not obvious what it should mean in any given context: it doesn't have an illustrative name. It's not always obvious that null means "no value for this parameter" -- heck, as a return value, sometimes it means "error", or even "success" (!!), or simply "the correct answer is nothing". Optional is frequently the concept you actually mean when you make a variable nullable, but not always. When it isn't, we recommend that you write your own class, similar to Optional but with a different naming scheme, to make clear what you actually mean.

But I would say the biggest advantage of Optional isn't in readability: the advantage is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things, and though FindBugs helps, I don't think it addresses the issue nearly as well. This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves.

For these reasons, we recommend that you use Optional as a return type for your methods, but not necessarily in your method arguments.

(This is totally cribbed, by the way, from the discussion here.)

Implementing Maybe/Option type in TypeScript using class inheritance

The minimal change to your code necessary to get it working would probably be this:

class None extends Maybe<never> {
constructor() { super(null!); }
}

That is, we are saying that None is a Maybe<never>, where the never type is the bottom type with no values. This is reasonable from a type system standpoint: the "right" type would be something like forall T. Maybe<T>, but since TypeScript doesn't have "generic values" like microsoft/TypeScript#17574 there's no way to express such a type directly. Since it looks like Maybe<T> should be covariant in T, then you could rephrase forall T. Maybe<T> as Maybe<forall T. T>, which would be equivalent to Maybe<never> as the intersection of all types in TypeScript is never.

But in order to construct a Maybe<never> with your code you need to supply a value of type never to the super constructor. This, of course, can't happen. You're passing null, which is not a never. We can use the non-null assertion operator (postfix !) to downcast null to never (the type of null! is NonNullable<null> which is never). This is technically a lie, but it's a fairly harmless one, especially if you never try to observe the value later.


If you want to be type safe everywhere then I think you'd need to refactor your base class so that it doesn't pretend to do things it can't do. A Maybe<T> might not have a value so value probably shouldn't be required in the base class. It could be optional:

abstract class Maybe<T> {
constructor(public value?: T) { } // <-- optional

unwrap(): T {
if (this.isSome()) return this.value; // reverse check
throw new Error('called unwrap() on None');
}

unwrapOr(defaultValue: T): T {
return this.isSome() ? this.value : defaultValue; // reverse check
}
}

class Some<T> extends Maybe<T> {
declare value: T // <-- narrow from optional to required
constructor(value: T) { super(value); }
}

class None extends Maybe<never> {
constructor() { super(); } // <-- don't need an argument now
}

And then you can declare the property in the subclass to be required (and I have to make it public since private doesn't let subclasses look at things and even protected gets iffy with those type guard functions you have). Note that I switched your checks from isNone() to isSome()... the Maybe<T> class is not known to be a union of Some<T> | None, so you can't use a false result of isNone() to conclude that this.value is present. Instead you should use a true result of isSome().


Finally, you could just move all the Some/None specific functionality out of Maybe, and then stop worrying about trying to force the base class to behave like both subclasses. Inheritance-based polymorphism tends to prefer subclasses to override methods instead of having a superclass method that checks for instanceof. This is similar to having Maybe just be an interface, with the exception of any truly polymorphic methods that don't need to check for the current class:

abstract class Maybe<T> {
abstract isSome(): this is Some<T>;
abstract isNone(): this is None;
abstract and<U>(other: Maybe<U>): Maybe<U>;
abstract unwrapOr(defaultValue: T): T;
}

class Some<T> extends Maybe<T> {
private value: T
constructor(value: T) { super(); this.value = value; }
isSome(): this is Some<T> { return true; }
isNone(): this is None { return false; }
and<U>(other: Maybe<U>) {
return other;
}
unwrap() { return this.value }
unwrapOr(defaultValue: T) { return this.value }
}

class None extends Maybe<never> {
isSome<T>(): this is Some<T> { return false }
isNone(): this is None { return true }
and<U>(other: Maybe<U>) {
return this;
}
unwrapOr<T>(defaultValue: T) { return defaultValue }
}

Here, there's nothing in Maybe except for abstract methods. If you can come up with something that doesn't need to check if this.isSome() or this.isNone() then it can go in the base class. The only noteworthy thing here is that some of the subclassing for Maybe<never> involves turning non-generic methods (isSome and unwrapOr) into generic methods.


Playground link to code

What is the point of final class in Java?

First of all, I recommend this article: Java: When to create a final class


If they do, when do they use it so I can understand it better and know when to use it.

A final class is simply a class that can't be extended.

(It does not mean that all references to objects of the class would act as if they were declared as final.)

When it's useful to declare a class as final is covered in the answers of this question:

  • Good reasons to prohibit inheritance in Java?

If Java is object oriented, and you declare a class final, doesn't it stop the idea of class having the characteristics of objects?

In some sense yes.

By marking a class as final you disable a powerful and flexible feature of the language for that part of the code. Some classes however, should not (and in certain cases can not) be designed to take subclassing into account in a good way. In these cases it makes sense to mark the class as final, even though it limits OOP. (Remember however that a final class can still extend another non-final class.)

scala How I can use get in class option

Basically, don't use get() ever. There's no situation in which it is a better choice than the alternatives. Option is a way of indicating in the type system that a function might not return what you want. You might think of it as a collection containing 0 or 1 things.

Take a look at the API docs which show several different ways to handle Option; as a collection using map/flatMap, getOrElse, for comprehensions, and pattern matching.

e.g. map:

val maybeData : Option[String] = Some("test")  // or None
val maybeResult = maybeData.map(x : String => doSomethingWithAString(x))

If maybeData is None, nothing happens. If it is Some() you will get back an Option containing the result of doSomethingWithAString(). Note that this will be Option[B] where B is the return type of doSomethingWithAString.

e.g. getOrElse:

val maybeData : Option[String] = Some("test")  // or None
val result : String = maybeData.getOrElse("N/A")

If data is Some, result is "test", otherwise it is "N/A".

e.g. pattern matching:

val maybeData : Option[String] = Some("test")  // or None
val result : String = maybeData match {
case Some(x) => doSomethingWithAString(x)
case None => "N/A"
}

You get the picture (note this assumes doSomethingWithAString returns String).

If you use get() and maybeData is None, you get the joy of handling the equivalent of nullpointers. Nobody wants that.

Min/max with Option[T] for possibly empty Seq?

Starting Scala 2.13, minByOption/maxByOption is now part of the standard library and returns None if the sequence is empty:

seq.minByOption(_.something)
List((3, 'a'), (1, 'b'), (5, 'c')).minByOption(_._1) // Option[(Int, Char)] = Some((1,b))
List[(Int, Char)]().minByOption(_._1) // Option[(Int, Char)] = None

Determining the type of an Option field in a Scala class

Using Java reflection quickly turned into a headache for me, so here is a pretty simple Scala solution:

import scala.reflect.runtime.universe._

//--Your case class definition--//

val values = typeOf[GenericCaseClass].members.filterNot(_.isMethod)

def prettyPrintField(symbol: Symbol): Unit = {
val name = symbol.name
val typeSignature: Type = symbol.typeSignature
println(s"$name: $typeSignature")
}

values.foreach(prettyPrintField)

Output:

r : Option[String]
q : Option[Char]
<- rest of fields ->
a : Boolean

Classes vs. Functions

Create a function. Functions do specific things, classes are specific things.

Classes often have methods, which are functions that are associated with a particular class, and do things associated with the thing that the class is - but if all you want is to do something, a function is all you need.

Essentially, a class is a way of grouping functions (as methods) and data (as properties) into a logical unit revolving around a certain kind of thing. If you don't need that grouping, there's no need to make a class.



Related Topics



Leave a reply



Submit