Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a function return one of multiple types which do not share a common ancestor?

Tags:

scala

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.)

like image 279
Ben Wilhelm Avatar asked Jan 19 '13 01:01

Ben Wilhelm


People also ask

Can a function return two types?

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.

Can Python function return different types?

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.

Can a function have multiple return types Python?

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.

Can methods have multiple return types?

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.

How to return a specific type of data from a function?

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.

What is the type of the result of the function?

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.

How to define a function with multiple return types in typescript?

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.

How to pass or return unrelated types from a method?

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.


1 Answers

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.

like image 153
sourcedelica Avatar answered Oct 29 '22 11:10

sourcedelica