views:

96

answers:

3

I have a case class which takes a list of functions:

case class A(q:Double, r:Double, s:Double, l:List[(Double)=>Double])

I have over 20 functions defined. Some of these functions have their own parameters, and some of them also use the q, r, and s values from the case class. Two examples are:

def f1(w:Double) = (d:Double) => math.sin(d) * w
def f2(w:Double, q:Double) = (d:Double) => d * q * w

The problem is that I then need to reference q, r, and s twice when instantiating the case class:

A(0.5, 1.0, 2.0, List(f1(3.0), f2(4.0, 0.5))) //0.5 is referenced twice

I would like to be able to instantiate the class like this:

A(0.5, 1.0, 2.0, List(f1(3.0), f2(4.0))) //f2 already knows about q!

What is the best technique to accomplish this? Can I define my functions in a trait that the case class extends?

EDIT: The real world application has 7 members, not 3. Only a small number of the functions need access to the members. Most of the functions don't care about them.

+1  A: 

One simple idea would be to change the function to take a list of functions that take 3 doubles (q, r, and s) and return a function from double to double. That way those functions that need any of the values can use them, and others just ignore them all.

pdbartlett
Interesting idea. I am worried this will clutter the function definitions. My example only has 3 members, but my real world application actually has 7. Also, only a few of the functions need access to the members. The majority don't care about them. I will add these details to the original question.
dbyrne
+3  A: 

There's the obvious val declaration:

val a = 0.5
A(a, 1.0, 2.0, List(f1(3.0), f2(4.0, a)))

Otherwise, f2 needs a reference to A's this, which it will have if it's a member of class A or that particular instance of A. Part of the problem is that the functions are fully baked before the instance of A is instantiated. So you have to define f2, as opposed to simply instantiate it, in the context of A.

Finally, you could make the functions partial functions. The first group of params will be as they are, but a second group will be added that is of type A.

sblundy
Which of these solutions would you be inclined to use? Is my idea of using a trait ill-conceived?
dbyrne
I guess defining the functions inside the class makes sense, since its unlikely they would be very useful elsewhere?
dbyrne
The trait idea is simply an extension of this idea. Depending on how much reuse you need, probably the best idea. If no reuse, just put 'em in A.
sblundy
+4  A: 

If q in f2 is always referring to the q in you case class, then one quick hack :

trait TraitA {                                                                                       
  def q:Double                                                                                       
  def r:Double                                                                                       
  def s:Double                                                                                       

  def f1(w:Double) = (d:Double) => math.sin(d) * w                                                   
  def f2(w:Double) = (d:Double) => d * q * w                                                         
}                                                                                                    

case class A(q:Double, r:Double, s:Double, l:List[(Double)=>Double]=Nil) extends TraitA              

val a=new A(0.5, 1.0, 2.0){override val l= List(f1(3.0), f2(4.0))}                                   
Patrick
Yes q in f2 always refers to q in the case class. This is exactly what I was considering doing, but not sure its a "best practice"?
dbyrne