0

New to scala and trying to get the hang of the class system. Here's a simple set up:

sealed trait Shape{
  def sides:Int
}

final case class Square() extends Shape {
  def sides() = 4
}

final case class Triangle() extends Shape {
  def sides() = 3
}

Now, I want to create a function that takes anything of type shape, which we know will have a sides() method implemented, and make use of that method.

def someFunction(a: Shape)={
    val aShape = a()
    aShape.sides()
}

But this hits an error at val aShape = a(), as there's no type a.

I realize that in this example, it's excessive to create someFunction, since sides() can be accessed directly from the objects. But my primary question is in the context of someFunction - I'd like to pass a class to a function, and instantiate an object of that class and then do something with that object. Thanks for your help.

keegan
  • 2,892
  • 1
  • 17
  • 20

4 Answers4

1

What are you trying to do with that line of code? You already have a shape, the one passed in called a. Just remove that line and call a.sides().

Stylistically, there are several problems. First of all, class names should start with a capital letter. Second, sides seems like an immutable property, not a mutating method, so it should be declared and overridden with no parentheses. You also need override modifiers in your subclass. Last, you can do without the empty braces: {4} should just be 4.

MattPutnam
  • 2,927
  • 2
  • 17
  • 23
1

There is several methods to do this. One is a complex one using reflection, second is little bit simplier, using a builder and third is most straightforward for your use case. Just change definition of someFunction to

def someFunction(a: ()=>Shape)={
  val aShape = a()
  aShape.sides
}

so someFunction(Square) return 4 and someFunction(Triangle) returns 3 . Note this work only with case classes because real thing, we are passing here is not class itself, but it's auto-generated companion object

But more often there no need to define classes, you could write inside any context except top level thing just like

def square() = new Shape{
  def sides() = 4
}

def triangle() = new Shape{
  def sides() = 3
}

Next thing: methods with empty parameter list are generally reading as method that have side effects. So it is more convenient to define your type like

sealed trait Shape{
  def sides:Int
}

and if you define your builders like

def square = new Shape{
  def sides = 4
}

def triangle = new Shape{
  def sides = 3
}

you should use them as someFunction(square _) telling, that you gonna use method call and not the value it's returning

And last thing is: if you really need the code, that creates some object, but it could contain complex computations, resource handling or some probable exception, so you want to hold over it's execution until it' really needed, you could use call-by-name parameters which is equivalent to R , which i assume you are familiar with

Community
  • 1
  • 1
Odomontois
  • 15,918
  • 2
  • 36
  • 71
0

Unless shape has an apply function, you cannot call () on a shape object.

If you want to assign aShape to a, simply write val aShape = a.

But since I do not see the added value, you might as well call the sides function directly on a:

def someFunction(a:shape) = {
  val sides = a.sides
  // use sides
}
Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
0

This is the closest translation for what you wrote:

sealed trait Shape {
  def sides: Int
}

case object Square extends Shape {
  override val sides = 4
}

case object Triangle extends Shape {
  override val sides = 3
}

def someFunction(a: Shape) =
  val shapeSides = a.sides

Some notes:

  • Classes in scala should be CamelCase
  • Your subclasses have no instance members, so you can use a singleton object
  • You if you have a: Shape it means that a is a Shape, and you haven't defined anything that would let you call () on it.
  • You can omit braces when there's only one expression inside
  • You can override a def with val if it's static
Daenyth
  • 35,856
  • 13
  • 85
  • 124
  • Thanks for your help. I realize that in this example, it's excessive to create `someFunction`, since `sides()` can be accessed directly from the objects. But my primary question is in the context of `someFunction` - I'd like to pass a class to that function, and instantiate an object of that class and then do something with that object. I'll clarify the question. – keegan Apr 27 '15 at 19:32
  • You wouldn't generally pass in a class and then create an instance, you pass in an instance. Do you want to create an instance based on number of sides input? What's the real problem you're trying to solve? – Daenyth Apr 27 '15 at 19:35
  • Thanks, I was thinking through this wrong, this helped clarify my understanding. I'll try to come up with a compact version of my actual problem. – keegan Apr 27 '15 at 19:38