scala self-type: value is not a member error
Asked Answered
W

2

0

This is a followup to this question.

I'm trying to implement vectors in scala with a generic super class using self-types:

trait Vec[V] { self:V =>
  def /(d:Double):Vec[V] 
  def dot(v:V):Double

  def norm:Double = math.sqrt(this dot this)
  def normalize = self / norm
}

Here's an implementation of a 3D vector:

class Vec3(val x:Double, val y:Double, val z:Double) extends Vec[Vec3]
{
  def /(d:Double) = new Vec3(x / d, y / d, z / d)
  def dot(v:Vec3) = x * v.x + y * v.y + z * v.z 
  def cross(v:Vec3):Vec3 = 
  {
      val (a, b, c) = (v.x, v.y, v.z)
      new Vec3(c * y - b * z, a * z - c * x, b * x - a * y)
  }

  def perpTo(v:Vec3) = (this.normalize).cross(v.normalize)
}

Unfortunately this doesn't compile:

Vec3.scala:10: error: value cross is not a member of Vec[Vec3]
  def perpTo(v:Vec3) = (this.normalize).cross(v.normalize)
                                        ^

What's going wrong, and how do I fix it?

Additionally, any references on self-types would be appreciated because I think these errors are cropping up from my lack of understanding.

Wage answered 23/1, 2011 at 22:4 Comment(0)
L
9

To get rid of all the nastiness, you have to specify that the type parameter V is a subclass of Vec. Now you can just use V everywhere, because your trait knows that V inherits all Vec[V] methods.

trait Vec[V <: Vec[V]] { self: V =>
  def -(v:V): V
  def /(d:Double): V
  def dot(v:V): Double

  def norm:Double = math.sqrt(this dot this)
  def normalize: V = self / norm
  def dist(v: V) = (self - v).norm
  def nasty(v: V) = (self / norm).norm
}

Note the method nasty which won’t compile with Easy Angel’s approach.

Licorice answered 23/1, 2011 at 23:10 Comment(1)
Thank you. I believe this is the proper answer to my original question: #4774111 . Would you mind posting there so I can give you points?Wage
M
3

I think, that method / in Vec should return V instead of Vec[V]:

trait Vec[V] { self:V =>
  def /(d:Double): V
  def dot(v:V):Double

  def norm:Double = math.sqrt(this dot this)
  def normalize = self / norm
}

method cross exists in Vec3 (or in other words in V) but not in Vec[V]

Manasseh answered 23/1, 2011 at 22:12 Comment(2)
What's the rule of thumb for when to use Vec[V] vs. V? The answer to the referenced question ( #4775243 ) was exactly the opposite, change return type V to Vec[V].Wage
I think this current issue has nothing to do with sef-types. normalize will just return Vec[V] and method cross is not defined there, but in your previous issue (this - v) returns V and in this context V is not considered to be Vec[V] by compiller because self-type declaration is unidirectional (as mentioned in comments).Manasseh

© 2022 - 2024 — McMap. All rights reserved.