Reputation:
Can you define a set of variables for later use?
Here are some pseudo code highlighting my intent:
def coordinates = x1, y1, x2, y2
log("Drawing from (%4.1f, %4.1f) to (%4.1f, %4.1f)".format(coordinates))
canvas.drawLine(coordinates, linePaint)
Here is a working example that contains duplicated code.
log("Drawing from (%4.1f, %4.1f) to (%4.1f, %4.1f)".format(x1, y1, x2, y2))
canvas.drawLine(x1, y1, x2, y2, linePaint)
Upvotes: 3
Views: 239
Reputation: 67828
Now, this may be obvious, but if it annoys you in only a few cases, you can always enhance:
implicit def enhancedCanvas(canvas: Canvas) = new {
// using bad and slow syntax. please change this in Scala 2.10.
def drawLineC(coordinates: (Float, Float, Float, Float), paint: Paint) = {
val (x1, y1, x2, y2) = coordinates
canvas.drawLine(x1, y1, x2, y2, paint)
}
}
Another possibility, if you’re crazy enough. (Might be that an enhancement like this is already in Scalaz or Shapeless.)
implicit def enhTuple4[A,B,C,D](t: Tuple4[A,B,C,D]) = new {
def |<[E] (f: (A, B, C, D) => E) = f(t._1, t._2, t._3, t._4)
}
// to be used as
val coordinates = (x1, y1, x2, y2)
coordinates |< (canvas.drawLine(_, _, _, _, linePaint))
Upvotes: 0
Reputation: 139028
Yes, you can, although the syntax is arguably horribly clunky, and there are some limitations that may seem a little arbitrary at first. The trick is to convert the method to a function (called "eta expansion"), and then to use that function's tupled
method to get something you can apply to a tuple.
Suppose you have a class like this:
class Foo {
def f(a: String, b: String) = "%s, %s".format(b, a)
def g(x: Int, y: Int, z: Int) = x + y * z
}
And an instance:
val foo = new Foo
And some data you'd like to use Foo
's methods on:
val names = ("John", "Doe")
val nums = (42, 3, 37)
You can't just write foo.f(names)
or foo.g(nums)
, because the types don't line up—argument lists and tuples are different things in Scala. But you can write the following:
scala> (foo.f _).tupled(names)
res0: String = Doe, John
scala> (foo.g _).tupled(nums)
res1: Int = 153
Sticking the underscore after the method turns it into a function (this is in my opinion the most confusing little quirk of Scala's syntax), and tupled
converts it from a function with two (or three) arguments to a function with a single tuple argument.
You could clean the code up a little by defining the following helper functions, for example:
scala> val myF = (foo.f _).tupled
myF: ((String, String)) => String = <function1>
scala> val myG = (foo.g _).tupled
myG: ((Int, Int, Int)) => Int = <function1>
scala> myF(names)
res2: String = Doe, John
scala> myG(nums)
res3: Int = 153
I'm not sure that's much better, though.
Lastly, you can't (conveniently) use this approach on a varargs method—you can't for example write the following:
val coordsTupleToString = ("(%4.1f, %4.1f) to (%4.1f, %4.1f)".format _).tupled
Or even just:
val coordsToString = "(%4.1f, %4.1f) to (%4.1f, %4.1f)".format _
Which is yet another reason to avoid varargs in Scala.
Upvotes: 5
Reputation: 340693
Looks like you need a tuple:
val coordinates = (x1, y1, x2, y2)
or maybe a full-blown object?
Upvotes: 2