Of course I realize all types do have a common ancestor, but what I mean is this:
In dynamically-typed languages, it is a common practice to have 'mixed' return types. A common case is a function which attempts to retrieve data from a database, then returns either an object (initialized with the found data) or FALSE (in the event no data was found).
A little pseudocode to demonstrate just such an anti-pattern:
function getObjectFromDatabase(object_id) {
if(result = db_fetch_object("SELECT * FROM objects WHERE id = %d", object_id) {
return result
} else {
return FALSE
}
}
If data is found for my object id, I get a DB record back as an object. If not, I get a boolean value. Then, of course, it is on me, the client, to handle multiple possible return types.
Is the only way to accomplish this in Scala to find a common ancestor for all possible return types and declare that as the return type in the signature?
// Like so:
def getObjectFromDatabase(objectId: Int): Any = {
val result = dbFetchObject("SELECT * FROM objects WHERE id = %d", object_id)
if(result) {
return result
} else {
return false
}
}
Or is it possible to annotate multiple possible return types?
(Note that I do not hope it is possible to do this, as I would prefer it to be enforced that function return types are as unambiguous as possible. It would come as a relief to me to learn that the language forbids ambiguous return types, which is more the reason I am asking.)
Because the function returns only 2 possible types, TypeScript knows that the type of the value is a number in the else block. How you narrow the type down might be different depending on the type of the values the function returns. For example, if you had to check for an array, you would use Array.
Python functions can return multiple variables. These variables can be stored in variables directly. A function is not required to return a variable, it can return zero, one, two or more variables. This is a unique property of Python, other programming languages such as C++ or Java do not support this by default.
Python functions can return multiple values. These values can be stored in variables directly. A function is not restricted to return a variable, it can return zero, one, two or more values.
As per the Java Language Specification, the methods in Java can return only one value at a time. So returning multiple values from a method is theoretically not possible in Java.
You can use templates, if you know what type to return before you call the function. But you can't have a function, which internally decide to return some type. What you can do is to create a class which will be a container for returned data, fill object of this class with desired data and then return this object.
The type of the value stored in result is a string in the if block. Because the function returns only 2 possible types, TypeScript knows that the type of the value is a number in the else block. How you narrow the type down might be different depending on the type of the values the function returns.
Use a union type to define a function with multiple return types in TypeScript, e.g. function getValue (num: number): string | number {}. The function must return a value that is represented in the union type, otherwise the type checker throws an error. Copied! We used a union type to set the return type of a function with multiple return types.
To truly pass or return unrelated types to or from a method, you want Union types which Java does not really support. But Paguro provides Union Types which you can use in Java like this (using Or): For your specific example, just use Floating Point.
Yes, use Either
:
def getObjectFromDatabase(objectId: Int): Either[Boolean, DbResult] = {
val result = dbFetchObject("SELECT * FROM objects WHERE id = %d", object_id)
if (result) Right(result) else Left(false)
}
getObjectFromDatabase(id) match {
case Right(result) => // do something with result
case Left(bool) => // do something with bool
}
Or, if the no results case doesn't need a specific value, use Option
:
def getObjectFromDatabase(objectId: Int): Option[DbResult] = {
val result = dbFetchObject("SELECT * FROM objects WHERE id = %d", object_id)
if (result) Some(result) else None
}
getObjectFromDatabase(id) match {
case Some(result) => // do something with result
case None => // do something about no results
}
See Tony Morris' Option Cheat Sheet for a list of the most common methods you can call on Option
and how they translate to pattern matching.
Two other alternatives are Validation
from scalaz and Try
, new in Scala 2.10.
For Validation
there are some really good answers on StackOverflow, for example: Method parameters validation in Scala, with for comprehension and monads.
For Try
see this blog post: The Neophyte's Guide to Scala Part 6: Error Handling With Try. The same author has good posts on Option
and Either
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With