6

In Scala, you can declare a variable by specifying the type, like this: (method 1)

var x : String = "Hello World"

or you can let Scala automatically detect the variable type (method 2)

var x = "Hello World"

Why would you use method 1? Does it have a performance benefit?
And once the variable has been declared, will it behave exactly the same in all situations wether it has been declared by method 1 or method 2?

Marco Prins
  • 7,189
  • 11
  • 41
  • 76
  • 1
    If it affects performance (and I don't think so) it's almost unnoticeable, it just shortens your code, in your case for example it's clear that x is a string. – Ende Neu Oct 30 '14 at 10:39
  • 5
    It does not, generate the exact same byte code. The most it could do is affect compiler speed. It makes no difference whatsoever at run time – Didier Dupont Oct 30 '14 at 10:52

4 Answers4

14

Type inference is done at compile time - it's essentially the compiler figuring out what you mean, filling in the blanks, and then compiling the resulting code.

What this means is that there can be no runtime cost to type inference. The compile time cost, however, can sometimes be prohibitive and require you to explicitly annotate some of your expressions.

Nicolas Rinaudo
  • 6,068
  • 28
  • 41
  • Are you sure? I don't think so. I think that in ensuring the types have been annotated, compiler would anyway need to do it's own inference and match it against yours, no? – 0fnt Nov 19 '14 at 12:55
  • 2
    Well, let me put it that way. If you type annotate a method, the compiler has exactly one type to check. If you don't, it has to check all of the types that could match the return value, and take the most restrictive one for which the rest of the program still type type checks. So, no, not quite the same thing. – Nicolas Rinaudo Nov 19 '14 at 13:50
  • I see. This explains. I'm a little rusty on my compiler concepts but thank you very much for the comment. – 0fnt Nov 19 '14 at 13:53
  • Hindley–Milner type system runtime cost is exponential. – vz0 Mar 12 '16 at 00:12
4

You will not have any performance difference using this two variants. They will both be compiled to the same code.

rtruszk
  • 3,902
  • 13
  • 36
  • 53
3

The other answers assume that the compiler inferred what you think it inferred.

It is easy to demonstrate that specifying the type in a definition will set the expected type for the RHS of the definition and guide type inference.

For example, in this method that builds a collection of something, A is inferred to be Nothing, which may not be what you wanted:

scala> def build[A, B, C <: Iterable[B]](bs: B*)(implicit cbf: CanBuildFrom[A, B, C]): C = {
     | val b = cbf(); println(b.getClass); b ++= bs; b.result }
build: [A, B, C <: Iterable[B]](bs: B*)(implicit cbf: scala.collection.generic.CanBuildFrom[A,B,C])C

scala> val xs = build(1,2,3)
class scala.collection.immutable.VectorBuilder
xs: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)

scala> val xs: List[Int] = build(1,2,3)
class scala.collection.mutable.ListBuffer
xs: List[Int] = List(1, 2, 3)

scala> val xs: Seq[Int] = build(1,2,3)
class scala.collection.immutable.VectorBuilder
xs: Seq[Int] = Vector(1, 2, 3)

Obviously, it matters for runtime performance whether you get a List or a Vector.

This is a lame example, but in many expressions you wouldn't notice the type of an intermediate collection unless it caused a performance problem.

Sample conversations:

https://groups.google.com/forum/#!msg/scala-language/mQ-bIXbC1zs/wgSD4Up5gYMJ

http://grokbase.com/p/gg/scala-user/137mgpjg98/another-funny-quirk

Why is Seq.newBuilder returning a ListBuffer?

https://groups.google.com/forum/#!topic/scala-user/1SjYq_qFuKk

Community
  • 1
  • 1
som-snytt
  • 39,429
  • 2
  • 47
  • 129
1

In the simple example you gave, there is no difference in the generated byte code, and therefore no difference in performance. It would also make no noticeable difference in compilation speed.

In more complex code (likely involving implicits) you could run into cases where compile-type performance would be noticeably improved by specifying some types. However, I would completely ignore this until and unless you run into it -- specify types or not for other, better reasons.

More in line with your question, there is one very important case where it is a good idea to specify the type to ensure good run-time performance. Consider this code:

val x = new AnyRef { def sayHi() = println("Howdy!") }
x.sayHi

That code uses reflection to call sayHi, and that's a huge performance hit. Recent versions of Scala will warn you about this code for that reason, unless you have enabled the language feature for it:

warning: reflective access of structural type member method sayHi should be enabled
by making the implicit value scala.language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scala docs for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.

You might then change the code to this, which does not make use of reflection:

trait Talkative extends AnyRef { def sayHi(): Unit }
val x = new Talkative { def sayHi() = println("Howdy!") }
x.sayHi

For this reason you generally want to specify the type of the variable when you are defining classes this way; that way if you inadvertently add a method that would require reflection to call, you'll get a compilation error -- the method won't be defined for the variable's type. So while it is not the case that specifying the type makes the code run faster, it is the case that if the code would be slow, specifying the type makes it fail to compile.

val x: AnyRef = new AnyRef { def sayHi() = println("Howdy!") }
x.sayHi  // ERROR: sayHi is not defined on AnyRef

There are of course other reasons why you might want to specify a type. They are required for the formal parameters of methods/functions, and for the return types of methods that are recursive or overloaded.

Also, you should always specify return types for methods in a public API (unless they are just trivially obvious), or you might end up with different method signatures than you intended, and then risk breaking existing clients of your API when you fix the signature.

You may of course want to deliberately widen a type so that you can assign other types of things to a variable later, e.g.

var shape: Shape = new Circle(1.0)
shape = new Square(1.0)

But in these cases there is no performance impact.

It is also possible that specifying a type will cause a conversion, and of course that will have whatever performance impact the conversion imposes.

AmigoNico
  • 6,652
  • 1
  • 35
  • 45