Both types Unit and Nothing indicate a function that does not return anything. What's the difference between them?
Unit is a type that has exactly one value ‒ see Unit type. On the other hand, Nothing has no possible value - see Bottom type.
A function that doesn't return anything must have the return type Unit. If it were Nothing then the function could not return a result. The only way to exit the function would be by an exception.
Nothing is used in a different way. It is characterized by two properties:
Nothing is a subtype of every other type (including Null).
There exist no instances of this type.
When is this useful? Consider None:
object None extends Option[Nothing]
Because Option is covariant in its type parameter and Nothing is a subtype of everything, Option[Nothing] is a subtype of Option[A] for every type A. So, we can make one object None which is a subtype of Option[A] for every A. This is reasonable, since Nothing cannot be instantiated so Option[Nothing] will always be without a value. Similarly
object Nil extends List[Nothing]
Unit corresponds to logical true and Nothing corresponds to logical false under the Curry-Howard isomorphism, where we view types as propositions and functions as proofs, .
Unit means that (a) function has side effects like input and output, (b) these side effects are the main goal of the function. Of course, a function can have side effects even if its type is different from Unit.
Nothing is a special type in Scala, because (a) it has no values (Unit has exactly one value - ()), so you cannot return a value of type Nothing, and (b) it is a subtype of every other type. That means that if something has the type Nothing, it can be used instead of any other type (via subtyping), but it won't produce any result. This is useful for dealing with exceptions - the throw expression has a type of Nothing, so it can be used everywhere in a program.
Simply, Nothing means that there was an error or termination of a program and nothing was returned, while Unit means there were side effects, but execution ended normally with no result.
Programming in Scala has a nice explanation of that.
To add one aspect to Petr's reply: Nothing plays an important role in the type hierarchy. It is a bottom type. That means that it is a subtype of every other type, which is like the opposite of Any, which is a supertype of everything. You can find a nice explanation here.
Unit
Unit is same as void of Java. void in java is a keyword but Unit is an Object in Kotlin.
Now if a function returns Unit in Kotlin, it means that it doesn't return anything meaningful, that function just executes a bunch of code and gives back the execution flow.
Nothing
Nothing is a different kind altogether. You can't relate it with anything in Java. There is nothing as such as Nothing in java.
Nothing means the end of execution. If a function returns Nothing, means literally nothing it returns. Not even the execution flow.
Nothing is like a black hole, anything that goes in doesn't come out, Not even the light (light is "execution flow" here). In the case of Unit, least light comes out.
So, if a function returns Nothing, the flow of code ends there and anything written after that is Unreachable.
Now see the code below,
fun main() {
unitFun()
println("after unit")
nothingFun()
println("after nothing") //you get warning here saying "unreachable code"
}
fun nothingFun(): Nothing {
println("inside nothing")
throw Exception()
}
fun unitFun(): Unit {
println("inside unit")
}
Output will be
inside unit
after unit
inside nothing
Exception in thread "main" java.lang.Exception
NOTE: you get warning as soon as you write
println("after nothing") UnReachable Code
And you know the reason, it's because nothingFun doesn't even send back the execution flow.
One more thing to complete this here is, any function that returns Nothing has to throw an exception of any kind.
REASON: If you write some general statement (and not throw an exception) then the function will match the return type and we don't have anything that returns Nothing, means we don't have anything that sucks the execution flow and never returns it back. Everything returns something, even Unit is something.
Now, one can say that Nothing is a class so we can make object of it and return that itself. Nohhhhhhh? A big nohhhh?
Nothing class has one constructor but it is private, so you can't even make an object of it.
Last Bit
Behind the scene, Unit is converted into void(small v) in the decompiled byte code while Nothing is converted into Void(capital V).
see the below code,
var user = null //First
var user : User? =null //Second
Here, the Second statement shows, user of Nullable-User type.
What is the type of user of the first statement?
any guess?
It's Nullable-Nothing type.
try to see the first statement as
var user : Nothing? = null
Now what's happening under the hood,
Void user = (Void)null; //First
User user = (User)null; //Second
Related
First of all, I'm very new to Scala and don't have any experience writing production code with it, so I lack understanding of what is considered a good/best practice among community. I stumbled upon these resources:
https://github.com/alexandru/scala-best-practices
https://nrinaudo.github.io/scala-best-practices/
It is mentioned there that throwing exceptions is not very good practice, which made me think what would be a good way to define preconditions for function then, because
A function that throws is a bit of a lie: its type implies it’s total function when it’s not.
After a bit of research, it seems that using Option/Either/Try/Or(scalactic) is a better approach, since you can use something like T Or IllegalArgumentException as return type to clearly indicate that function is actually partial, using exception as a way to store message that can be wrapped in other exceptions.
However lacking Scala experience I don't quite understand if this is actually viable approach for a real project or using Predef.require is a way to go. I would appreciate if someone explained how things are usually done in Scala community and why.
I've also seen Functional assertion in Scala, but while the idea itself looks interesting, I think PartialFunction is not very suitable for the purpose as it is, because often more than one argument is passed and tuples look like a hack in this case.
Option or Either is definitely the way to go for functional programming.
With Option it is important to document why None might be returned.
With Either, the left side is the unsuccessful value (the "error"), while the right side is the successful value. The left side does not necessarily have to be an Exception (or a subtype of it), it can be a simple error message String (type aliases are your friend here) or a custom data type that is suitable for you application.
As an example, I usually use the following pattern when error handling with Either:
// Somewhere in a package.scala
type Error = String // Or choose something more advanced
type EitherE[T] = Either[Error, T]
// Somewhere in the program
def fooMaybe(...): EitherE[Foo] = ...
Try should only be used for wrapping unsafe (most of the time, plain Java) code, giving you the ability to pattern-match on the result:
Try(fooDangerous()) match {
case Success(value) => ...
case Failure(value) => ...
}
But I would suggest only using Try locally and then go with the above mentioned data types from there.
Some advanced datatypes like cats.effect.IO or monix.reactive.Observable contain error handling natively.
I would also suggest looking into cats.data.EitherT for typeclass-based error handling. Read the documentation, it's definitely worth it.
As a sidenote, for everyone coming from Java, Scala treats all Exceptions as Java treats RuntimeExceptions. That means, even when an unsafe piece of code from one of your dependencies throws a (checked) IOException, Scala will never require you to catch or otherwise handle the exception. So as a rule of thumb, when using Java - dependencies, almost always wrap them in a Try (or an IO if they execute side effects or block the thread).
I think your reasoning is correct. If you have a simple total (opposite of partial) function with arguments that can have invalid types then the most common and simple solution is to return some optional result like Option, etc.
It's usually not advisable to throw exceptions as they break FP laws. You can use any library that can return a more advanced type than Option like Scalaz Validation if you need to compose results in ways that are awkward with Option.
Another two alternatives I could offer is to use:
Type constrained arguments that enforce preconditions. Example: val i: Int Refined Positive = 5 based on https://github.com/fthomas/refined. You can also write your own types which wrap primitive types and assert some properties. The problem here is if you have arguments that have multiple interdependent valid values which are mutually exclusive per argument. For instance x > 1 and y < 1 or x < 1 and y > 1. In such case you can return an optional value instead of using this approach.
Partial functions, which in the essence resemble optional return types: case i: Int if i > 0 => .... Docs: https://www.scala-lang.org/api/2.12.1/scala/PartialFunction.html.
For example:
PF's def lift: (A) ⇒ Option[B] converts PF to your regular function.
Turns this partial function into a plain function returning an Option
result.
Which is similar to returning an option. The problem with partial functions that they are a bit awkward to use and not fully FP friendly.
I think Predef.require belongs to very rare cases where you don't want to allow any invalid data to be constructed and is more of a stop-everything-if-this-happens kind of measure. Example would be that you get arguments you never supposed to get.
You use the return type of the function to indicate the type of the result.
If you want to describe a function that can fail for whatever reason, of the types you mentioned you would probably return Try or Either: I am going to "try" to give your a result, or I am going to return "either" a success or an failure.
Now you can specify a custom exception
case class ConditionException(message: String) extends RuntimeException(message)
that you would return if your condition is not satisfied, e.g
import scala.util._
def myfunction(a: String, minLength: Int): Try[String] = {
if(a.size < minLength) {
Failure(ConditionException(s"string $a is too short")
} else {
Success(a)
}
}
and with Either you would get
import scala.util._
def myfunction(a: String, minLength: Int): Either[ConditionException,String] = {
if(a.size < minLength) {
Left(ConditionException(s"string $a is too short")
} else {
Right(a)
}
}
Not that the Either solution clearly indicates the error your function might return
If I have a JsValue, which method shall I use to get values from the JsValue: Json.fromJson, as, asOpt and validate?
It depends on the level of error handling you want.
What as, asOpt, and validate all have in common is that they will attempt to de-serialize a JsValue into the type T you specify, using whatever implicit Reads[T] can be resolved. Where they differ is how they behave, and what types they return.
Let's say we're working with a class Foo where we have an implicit Reads[Foo] already defined.
as[Foo] will simply try to convert a JsValue into a Foo, and if it fails, it will throw an exception. This is not a safe thing to do, as the only way to handle the error would be to catch the exception and deal with it, which you might not remember to do. JSON failing to map to a certain type is rarely an exceptional case, either--it happens all the time. as should be used rarely, at most.
asOpt[Foo] will try to convert a JsValue into a Foo, and if it fails, it will simply return None. If it's successful, it will return the de-serialized value wrapped in Some. This is much better than as, since you are forced to confront the failure case (unless you do something silly like call .get). The downside is, all of the errors are swallowed when converting the failure to None, so you have no idea why it failed. If you don't care, using asOpt is perfectly fine.
validate[Foo] will try to convert a JsValue into a Foo, and will always return a JsResult[Foo]. If the conversion is successful, it will be a JsSuccess[Foo] that contains the de-serialized value. If it fails, it will be a JsError that contains all of the error information such as what paths are missing and what types do not match what they are expected to be. You can use the fold method on JsResult to safely handle each case. For example:
js.validate[Foo].fold(
errors => /* Do something with the errors */ ,
foo => /* Do something with Foo */
)
Json.fromJson does the exact same thing as JsValue#validate. They both call the underlying Reads to return a JsResult.
So usually when we run a method that can both fail and return a value, we can encode our method return type as Either[SomeErrorType, ReturnType]. But many times we're running a method for its side effects, so the return type is Unit.
I could of course return an Either[SomeErrorType, Unit] but that definitely looks odd.
I could also just return an Option[SomeErrorType] but it doesn't really look a lot better (and breaks a possibly existing symmetry with other Either[SomeErrorType, NonUnitReturnType]s.
What's your approach in these cases?
def m(): Unit // and implicitly know that exceptions can be thrown?;
def m(): Either[SomeErrorType, Unit] // this is odd;
def m(): Option[SomeErrorType] // this is odd, as it makes it look as the return type ofm()on a successful run is an error code.
Other that I can't think of?
Thanks
I use Try[Unit] for that case.
It encodes that the result of the method either succeeds or fails with some Exception, which can be further processed.
vs T => Unit Try lifts errors to the application level, encoding in the signature that some error can be expected and allowing the application to handle it as a value.
vs. Option[T] => Option is only able to encode that the operation had a value or not
vs. Either[SomeErrorType, Unit] => Try It's easier to work with using monadic constructions.
I've used something like this to implement checks. (imaginary example)
for {
entity <- receiveEntity // Try[Entity]
_ <- isRelational(entity)
_ <- isComplete(entity)
_ <- isStable(entity)
} yield entity
where each check is of the form: Entity => Try[Unit]
This will return the entity if all checks pass of the first error that failed the check.
One more option that hasn't been mentioned yet is Validated from cats. All the options mentioned so far (Try, Either, Option) are monads, while Validated is an applicative functor. In practice this means you can accumulate errors from multiple methods returning Validated, and you can do several validations in parallel. This might not be relevant to you, and this is a bit orthogonal to the original question, but I still feel it's worth mentioning in this context.
As for the original question, using Unit return type for a side-effecting function is perfectly fine. The fact this function can also return error shouldn't get in your way when you define the "real" (right, successful, etc.) return type. Therefore, if I were to select from your original options, I'd go for Either[Error, Unit]. It definitely doesn't look odd to me, and if anyone sees any drawbacks in it, I'd like to know them.
According to the documentation:
The Try type represents a computation that may either result in an
exception, or return a successfully computed value. It's similar to,
but semantically different from the scala.util.Either type.
The docs do not go into further detail as to what the semantic difference is. Both seem to be able to communicate successes and failures. Why would you use one over the other?
I covered the relationship between Try, Either, and Option in this answer. The highlights from there regarding the relationship between Try and Either are summarized below:
Try[A] is isomorphic to Either[Throwable, A]. In other words you can treat a Try as an Either with a left type of Throwable, and you can treat any Either that has a left type of Throwable as a Try. It is conventional to use Left for failures and Right for successes.
Of course, you can also use Either more broadly, not only in situations with missing or exceptional values. There are other situations where Either can help express the semantics of a simple union type (where value is one of two types).
Semantically, you might use Try to indicate that the operation might fail. You might similarly use Either in such a situation, especially if your "error" type is something other than Throwable (e.g. Either[ErrorType, SuccessType]). And then you might also use Either when you are operating over a union type (e.g. Either[PossibleType1, PossibleType2]).
Since Scala 2.12, the standard library does include the conversions from Either to Try or from Try to Either. For earlier versions, it is pretty simple to enrich Try, and Either as needed:
object TryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] =
t.map(Right(_)).recover(Left(_)).get
}
}
This would allow you to do:
import TryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)
To narrowly answer your question: "What's the semantic difference":
This probably refers to flatMap and map, which are non-existent in Either and either propagate failure or map the success value in Try. This allows, for instance, chaining like
for {
a <- Try {something}
b <- Try {somethingElse(a)}
c <- Try {theOtherThing(b)}
} yield c
which does just what you'd hope - returns a Try containing either the first exception, or the result.
Try has lots of other useful methods, and of course its companion apply method, that make it very convenient for its intended use - exception handling.
If you really want to be overwhelmed, there are two other classes out there which may be of interest for this kind of application. Scalaz has a class called "\/" (formerly known as Prince), pronounced "Either", which is mostly like Either, but flatMap and map work on the Right value. Similarly, and not, Scalactic has an "Or" which is also similar to Either, but flatMap and map work on the Left value.
I don't recommend Scalaz for beginners.
Either does not imply success and failure, it is just a container for either an A or a B. It is common to use it to represent successes and failures, the convention being to put the failure on the left side, and the success on the right.
A Try can be seen as an Either with the left-side type set to Throwable. Try[A] would be equivalent to Either[Throwable, A].
Use Try to clearly identify a potential failure in the computation, the failure being represented by an exception. If you want to represent the failure with a different type (like a String, or a set of case classes extending a sealed trait for example) use Either.
Either is more general, since it simply represents disjoint unions of types.
In particular, it can represent a union of valid return values of some type X and Exception. However, it does not attempt to catch any exceptions on its own. You have to add try-catch blocks around dangerous code, and then make sure that each branch returns an appropriate subclass of Either (usually: Left for errors, Right for successful computations).
Try[X] can be thought of as Either[Exception, X], but it also catches Exceptions on its own.
Either[X, Y] usage is more general. As its name say it can represent either an object of X type or of Y.
Try[X] has only one type and it might be either a Success[X] or a Failure (which contains a Throwable).
At some point you might see Try[X] as an Either[Throwable,X]
What is nice about Try[X] is that you can chain futher operations to it, if it is really a Success they will execute, if it was a Failure they won't
val connection = Try(factory.open())
val data = connection.flatMap(conn => Try(conn.readData()))
//At some point you can do
data matches {
Success(data) => print data
Failure(throwable) => log error
}
Of course, you can always oneline this like
Try(factory.open()).flatMap(conn => Try(conn.readData()) matches {
Success(data) => print data
Failure(throwable) => log error
}
As already have been mentioned, Either is more general, so it might not only wrap error/successful result, but also can be used as an alternative to Option, for branching the code path.
For abstracting the effect of an error, only for this purpose, I identified the following differences:
Either can be used to specify a description of the error, which can be shown to the client. Try - wraps an exception with a stack trace, less descriptive, less client oriented, more for internal usage.
Either allows us to specify error type, with existing monoid for this type. As a result, it allows us to combine errors (usually via applicative effects). Try abstraction with its exception, has no monoid defined. With Try we must spent more effort to extract error and handle it.
Based on it, here is my best practices:
When I want to abstract effect of error, I always use Either as the first choice, with List/Vector/NonEmptyList as error type.
Try is used only, when you invoke code, written in OOP. Good candidates for Try are methods, that might throw an exception, or methods, that sends request to external systems (rest/soap/database requests in case the methods return a raw result, not wrapped into FP abstractions, like Future, for instance.
I am not sure what the difference is between specifying Unit as the return type of my scala method or leaving out the return type altogether. What is the difference?
Can anyone please advise?
Implicit Unit return type:
def f() {println("ABC")}
Explicit Unit return type:
def g(): Unit = {println("ABC")}
Return type inferred from the last method expression, still Unit because this is the type of println, but confusing:
def h() = println("ABC")
All the methods above are equivalent. I would prefer f() because the lack of = operator after method signature alone is enough for me. Use explicit : Unit when you want to extra document the method. The last form is confusing and actually treated as a warning in intellij-idea.
The = operator is crucial. If it is present it means: "please return whatever the last statement returns" in method body. Obviously you cannot use this syntax for abstract methods. If it is not, Unit is assumed.
The special syntax for procedures (methods returning Unit) was a mistake. Don't use it. It is confusing and dangerous for beginners with a Java/C(++) background. And it is a unnecessary special treatment. Always use the equal sign, with and without type inference (the latter should only be used for private members):
def foo(): Unit = someCodeReturningUnit()
private def bar() = someCodeReturningUnit()
The Scala community is divided about it. On the one hand, not using explicit return types means you can easily forget the = sign, which results in errors that are often annoying to track. On the other hand, Unit-returning methods having a different syntax puts them in a separate category, which pleases some people.
Personally, I'd rather this syntax would go away -- the errors resulting from missing = are annoying to track. But it's not even deprecated, so I'd rather take advantage of it than just suffer the problems of its existence.
So, use whatever you wish. There's going to be people criticizing your choice either way, and people praising it either way.