score:1
Maybe if the order doesn't matter. So unlike in your firstName/lastName example, where there is a distinction.
There is still no information available, what the values are, but in a generic case, there might be no information.
score:4
IMHO, as a general rule:
- By default, you should prefer case class: it doesn't cost more and it is much clearer
Also, case class provides lots of practical functionalities, such as apply, unapply and copy(from comment: tuples also have those)- And tuples of length > 3 should be avoided in general
But:
- For methods that have several outputs, which are typically split right-away. Then use tuple
- In several algorithms, especially using functional map/flatMap/etc..., you have lot's of intermediate "one-line" results for which you don't need to define a case class.
- Finally, as stated by andrey-tyukin, if you're coding generic-type algorithms you could prefer tuples. But then, you can actually do nice generic case-class code using shapeless magic
A last comment, concerning type alias: I use those mainly to improve readability when I don't want to create classes. This happens in two cases:
- the aliased type is a primitive, such as Int or Double, that is used in critical code and I want to avoid boxing them (note that this requires to respect other constraints to be effective)
- when a single type has many meanings but creating a case class would be over-design. Ex. say several APIs use
param: Map[String, Double]
. Map is a good type and you don't want to wrap it in a class. Then it may be more readable to haveApiParams
in your code wheretype ApiParams = Map[String, Double]
score:14
You should use tuples when it is the most appropriate level of abstraction.
For example, if you are writing a framework where everything is completely generic, and the most concrete things that you can get are "functions", "cartesian products", "semigroupals", or something like "closed monoidal categories", then you probably will have no other choice but using Tuple
. Here is one good example: Semigroupal with method:
product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
Here, the usage of the tuple type is completely justified, because the interface is sufficiently abstract.
Another example: in the entire Scala collection library, you will never encounter anything as concrete as Person(name: String, surname: String)
, but instead you will see a huge lot of methods that work on tuples of generic types (A, B)
.
However, if the most abstract thing in your code is
object Fred {
val name = "Fred"
val surname = "Bloggs"
}
and then you suddenly find out that you also need another similar object for John Doe
, it would be much more appropriate to define
case class Person(name: String, surname: String)
and then maybe even to use it like this:
val j = Person(name = "John", surname = "Doe")
Of course, there is great value in accurately modeling the domain. These two goals -- accurately modeling a concrete domain vs. writing generic frameworks that work in as many cases as possible -- are complementary.
To summarize:
- Are you writing a sufficiently abstract completely generic framework? Use tuples.
- Are you trying to model some concrete domain as closely as possible? Use appropriately named case classes.
This here:
type Person = (String, String) //firstName, lastName
looks like a mismatch between the domain and the used abstraction. You can see it simply from the fact that the compiler does not prevent you from accidentally swapping the two components. In contrast, if you worked at a different abstraction level with generic A
and B
types, the compiler would emit an error message if you accidentally swapped (B, A)
where an (A, B)
was expected.
Source: stackoverflow.com
Related Query
- When does it make sense to use tuples over case class
- When does it make sense to use implicit parameters in Scala, and what may be alternative scala idioms to consider?
- Does it make sense to define a class for Complex numbers, where real/imaginary parts use Numeric[T] instead of a concrete type?
- Do two copies of a case class use twice the memory when only one property is changed, or does Scala reuse immutable values on copy to save memory?
- Does it make sense to use Paging SQL Statement when using Slick (JDBC) Connector for Alpakka
- When to use case class or regular class
- Circe - Use default fields in case class when decoding/encoding json
- Does it make sense to use a pool of Actors?
- Does it make any sense to use pattern matching in Scala with really simple cases?
- If data fits on a single machine does it make sense to use Spark?
- Scala - looping over case class names to use as type parameters
- Why I can't use "tupled" of case class when I add companion object?
- Equality of Scala case class does not work in junit assertEquals when it contains an inner Array
- Using Vaadin with Scala - does it make sense to use framework like Play! or Lift?
- Does it make sense to use "private[this] lazy val"?
- Does it make sense to have properties like Option[List[...]] when the List container supports the property of empty?
- Error when use akka http unmarshall entity as case class with default value
- "Forward reference extends over definition value exp" when using an abstract class with case classes of a Scala tutorial
- Use case class copy method and abstract over named parameters
- How to make a method taking any case class as a argument and use it as type
- Reflection does not see companion of subclass case class when defined in companion of extending trait
- Scala case class member parameterized with wildcard types does not infer type bound when called
- How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration
- Should I use the final modifier when declaring case classes?
- How to turn json to case class when case class has only one field
- Passing enum parameter to a case class does not work
- Scala - No TypeTag Available Exception when using case class to try to get TypeTag?
- What does the @elidable annotation do in Scala, and when should I use it?
- How to use a case classes when hierarchy is needed?
- when to use Classes vs Objects vs Case Classes vs Traits
More Query from same tag
- Recursively transform json in play
- How to write generic method for automatic type resolution on call?
- How to know the mailbox is empty for unstashing and sending the low priority messages?
- Akka-stream: onComplete called before mapAsync has finished to process data
- SBT stop run without exiting
- What is the Scala equivalent of the `this` operator in Java?
- Eclipse can't build automatically
- sbt for web app with command line code
- Sse stream crashed io.gatling.http.action.sse.SseInvalidContentTypeException: Server returned http response with content-type null
- How can I test a method which calls error() with specs2?
- Scala Slick 3.0.0 Strange Error
- Is the arrow anti pattern a standard in Scala
- How to Fix Ambiguous Reference to Overloaded apply() method when deserializing Json
- How to count number of directory in S3 using spark scala?
- What is "$ play test" dropdown in circleCI?
- Scalikejdbc query results as a stream
- Using Akka Dispatchers for Handling Futures
- How to run sbt multiple command in interactive mode as one command?
- Insert tokens into a string dynamicaly Scala
- How do I skip a header from CSV files in Spark?
- cannot resolve explode due to type mismatch in spark while parsing xml file
- Best practice for Slick 2.1 / 3 execution context usage
- How can I get the request object in play2 framwork(scala)
- Dynamic polymorphism in Scala
- Unable to create dataframe from a textfile using case class in spark scala
- Create a function that returns the logical OR of several boolean predicates
- What would be the best practice of Scala to have a method accept two different models
- Spark TaskNotSerializable when using anonymous function
- What's wrong with the following Scala code?
- NoSuchMethodException: scala.tools.nsc.interpreter.ILoop.scala when running pyspark code zepplin