2 function parameters of same type

From time to time I have a function (or method) which has two parameters of the same type, but the type name is long to type. I’m not sure whether it is good practice in terms of readability , but I often name the type with a type alias, and use that type alias in the declaration.

Is there a better way? I think there is no Scala syntax for declaring multiple arguments of the same type, other than just typing the type name twice.

An alternative might be to use a type parameter, and just let the compiler figure out the type. That’s less typing, but potentially more confusing to the next person who tries to read my code.

E.g.

  type QMUP = (Clause, Int, Int, Clause)
  type REMADD = (List[QMUP], List[QMUP])

  def foldups(ups: Iterable[REMADD]): REMADD = {
    ups.fold((Nil, Nil)) { case ((r, a), (removes, adds)) => (removes ++ r, adds ++ a) }
  }
    def calcNextPhase(removes: List[QMUP], adds: List[QMUP]): Set[(Int, Int, Clause)] = {
      import accumulators.Accumulators._
      for {
        (clause, posCount, length, rectified) <- removes
      } removeClause(clause, posCount, length, rectified)
      withSetCollector(collect =>
                         for {
                           (clause, posCount, length, rectified) <- adds
                           _ = addClause(clause, posCount, length, rectified)
                         } collect((posCount, length, rectified)))
    }

Nothing wrong about using type aliases - not only to save typing, but more generally to have more precise names for my types. In your example I’d probably be tempted to use proper case classes, though - the type QMUP doesn’t tell anything about the meaning of the Clause and Int components of the tuple…

I considered whether to use case classes. I wonder what the memory requirements will be. I’m assuming tuples are more light weight. My application may be handling many 100s of 1000s of such structures. On the other hand as we say in Lisp, premature optimization is the root of all even.
So perhaps I’m optimizing too early at the expense of readability???

I made your suggested change in my code, i.e., the change to case classes. Without question, it makes the code simpler.

I haven’t tried examining it carefully, but I suspect you are wrong. Tuples and case classes are pretty similar in many ways, and I have no reason to believe that a case class would be more expensive in any significant way. (The case class generates a bit more code, but that’s usually the tiniest drop in the bucket for a typical application.)

As a rule of thumb, idiomatic Scala code tends to use case classes, and only uses tuples for the simplest situations. In general, once it has more than two elements, I will usually switch to a case class.

A tuple is a case class itself, so there’s no way an instance of custom case class would weight more. In fact often a tuple will weight more than a custom case class as tuples are fully generic thus always boxing the inner items unless specialized. Only Tuple1 and Tuple2 are specialized and still not fully. See:
https://github.com/scala/scala/blob/v2.13.0/src/library/scala/Tuple1.scala (specialized on 3 types)
https://github.com/scala/scala/blob/v2.13.0/src/library/scala/Tuple2.scala (specialized on 5 x 5 types)
https://github.com/scala/scala/blob/v2.13.0/src/library/scala/Tuple3.scala and higher (totally unspecialized i.e. always boxing the inner items)

2 Likes

Tuples are regular objects. (A, B, C) is just syntactic sugar for Tuple3[A, B, C].

You could make the argument that, if you create a dozen classes, your app needs to load and store a dozen class definitions, but if you use, say, Tuple3 each time instead, it only needs to load and store one class definition instead of a dozen.

I don’t know how large a class definition is, but I’ve never heard it being such a concern that people are trying to reuse classes.