2014-12-23 3 views
5

var이 서브 클래스와 그 반대의 val을 무시할 수없는 이유를 이해하는 동안, 나는 스칼라 var으로 슈퍼 클래스왜 스칼라에서`def`로`var`을 오버라이드하는 것이 불가능합니까?

class Car { 
    var age = 32 
} 

class SedanCar extends Car { 
    override def age = 54 
} 

var을 무시할 서브 클래스에 def을 허용하지 않는 이유를 이해 할 수없는 이유를 변경할 수 있습니다입니다 def에서 재정의 할 수 없습니까? 아무도 이해를 도와 줄 수 있습니까?

+1

def는 변경 가능하지 않고, 메소드 정의이기 때문에. SedanCar에서'age = 32'를하면 어떻게되고 싶습니까? –

+5

OP의 질문은 완전히 합리적이라고 생각합니다. 스칼라는 종종 정당한 이유 때문에 균일 액세스 원칙을 준수하는 것으로 제시됩니다. 'age' var 정의를 한 쌍의 getter와 setter ('age'와'age_ =') 메소드의 정의 이상으로 보는 것은 무리가 아닙니다. 어떤 경우에 나는 확실히'age'를 오버라이드 할 수 있어야합니다.'age'는 실제로 getter만을 오버라이드하고 setter는 그대로 둡니다. –

답변

12

Liskov Substitution Principle과 관련이 있습니다. weaker access privileges in subclass (even for Java)을 할당 할 수 없습니다. vardef으로 설정하면 설정자 def x_= (y: T): Unit이 비공개가됩니다 (@Staix에서 말한대로). 따라서 Seadan Car에 공식 형식 Car이있는 경우 액세스해서는 안되지만 일반적으로 컴파일러에서는 이러한 형식을 찾을 수 없으므로 (공식 형식 만 컴파일 타임에 알려져 있음) 더 약한 권한처럼 이러한 동작을 사용할 수 없게됩니다.

val car2 = new SeadanCar 

car.age = 422 //compiler error, can't mutate "def age" 

val car: Car = new SeadanCar 

car.age = 42 //now you had mutated immutable 

대체 성의 원칙은 상위 유형으로 변환 한 후에 동작을 변경하지 말아야한다는 것입니다.

한편 스칼라는 @ Régis Jean-Gilles에 따르면 변수의 getter 부분 만 무시할 수 있지만 직관적으로 사용자가 varoverride def 이후에 불변이 될 것으로 예상하기 때문에이 해결책이 아닙니다. var을 실제로 하나가 아닌 두 개의 서비스 (리더 및 라이터)로보아야하므로 실제로는 Uniform Access Principle을 위반하고 있습니다. 반면 UAP 호환에는 반대가 필요합니다. 리더와 작가 모두 하나의 통일 표기법으로 표현되어야합니다.

P. 사실 귀하의 질문은 스칼라의 UAP 호환성 불완전 성을 지적합니다. 내가 말했듯이 var의 리더를 무시하고 writer를 그대로 두는 것은 UAP와 일치하지 않습니다. var 자체를 덮어 쓰는 기능이 차단되어 있습니다 (따라서 계산 및 저장과 같은 두 가지 방식으로 var를 재정의 할 수 없습니다). 당신은 이미 LSP 때문에 그것을 무시할 수 없습니다. 그러나 현재의 스칼라의 해결책은 또한 문제가있다.

trait Car { def age: Int = 7; def age_=(a: Int) = {}} 

class SeadanCar extends Car { override def age: Int = 5} 

을하지만 할 수 없습니다

// just repeating your example 

trait Car { var age: Int = 7 } 

class SeadanCar extends Car { override def age: Int = 5} 

그래서 스칼라의 상속는 UAP와 호환되지 않는 것 : 당신은 당신이 할 수있는 것을 알 수 있습니다. IMHO, 가장 큰 문제는 독자와 var 자체가 동일한 이름을 가지고 있기 때문에 (정의 할 때, 액세스하지 않을 때) 구분할 수 없기 때문입니다.

scalaxx> (new SeadanCarReadOnly).age //call age_ here 
resxx: Int = 5 

scalaxx> (new SeadanCarReadOnly).age_ 
resxx: Int = 5 

이 좋아되지 않음 :에 내 제안 예에 age_을 무시하는 것이 될 것을,

trait Car { def age_: Int = 7; def age_=(a: Int) = {}} 
class SeadanCarReadOnly extends Car { override def age: Int = 5} //can't compile as reader is closed 
class SeadanCarVar extends Car { override var age: Int = 5} 
class SeadanCarReadOnly extends Car { override def age_: Int = 5} 

trait Car2 { var age = 100500 } 
class SeadanCarReadOnly extends Car2 { override def age_: Int = 5} 

참고 : 내가 좋아하는 뭔가를 해결할 것 cource의

trait Car2 { @BeanProperty var age = 100500 } 
class SeadanCarReadOnly extends Car2 { override def getAge: Int = 5} 

//which leads to inconsistency: 

scala> (new SedanCar()).age 
res6: Int = 30 

scala> (new SedanCar()).getAge 
res7: Int = 54 

등 접근 방식은 var agedef age_; def age_=을 동시에 무시하는 것이 좋습니다.

,210
trait Car2 { var age = 100500 } 
class SeadanCarReadOnly extends Car2 { 
    override var age = 17; 
    override def age_: Int = 5 //should be compile error here 
} 

하지만이 때문에 문제의 가변성/immutabilty 부분에 대한

PS/2는 그냥 언급 이전 버전과의 호환성, 신속 스칼라 언어로 구현하기 어려운, 너 확실히 (이 작업을 수행 할 수 없습니다 때문에) LSP에 :

trait Car { def age: Int = 7; def age_=(a: Int) = {}} 
class SedanCar extends Car { override val age = 42 } 

regardl :

trait Car { var age: Int = 32 } //or without initial value 
class SedanCar extends Car { override val age = 42 } 

그리고 인해 LSP + UAP에,이 작업을 수행 할 수 없게한다 사실 당신이 할 수있는 사실 :

+1

"사용자가 기대하는 부분"을 구입할 수는 있지만 유감스럽게도 getter 만 재정의하면 UAP를 위반하게됩니다. 결국,'age'만을 참조하여'age'를 읽거나 쓸 수 있습니다. 나는 그것이 "통일 표기법"의 더 많은 것을 할 수있는 방법을 보지 못한다. 나는이 한계에 대한 이유를 생각할 수 있지만, UAP를 깨는 것은 그 중 하나가 아니라, 그 반대입니다. –

+0

사이드 노트로서 저는 실제로 게터를 오버라이드 할 수 없다는 점을별로 신경 쓰지 않습니다. 그러나 실제로 var를 오버라이드 할 수는 없으며 하나의 변수는 파격적입니다. –

+0

1)'var'은 통일 표기법이고,'get' +'set'은 없습니다. 당신이 말할 때 "그냥 무시하자!" - 당신은 분명히 두 번째를 선호하고 getters/setter에 대해 생각하도록 사용자를 밀고 있습니다. 2) 나는 공식적인 타입을 가진 나의 예제가 var "at"를 오버라이드 (override) 할 수없는 이유를 충분히 나타낼 수 있다고 생각한다. – dk14

0

개념에 문제가 있다고 생각합니다. 스칼라 참조에서 :

변수 선언 var에 X :

def x: T 
def x_= (y: T): Unit 
그래서

재정의하려고 다음과 같이 T 네드 getter 함수 X 와 세터 기능 X_ = 드 Fi를 선언하는 것과 같습니다 "나이 = 54"에의 한 취득자. 하지만 이제는 세터에게 아무런 쓸모가 없습니다.

희망을 의미합니다. Scala의 사고 방식에 대해 생각하지 않으므로 왜 사람들이 질문을 "제외"하는지 생각합니다.

+4

당신의 대답은 이슈의 핵심을 정확하게 지적합니다 :'var x : T'는'def x : T;와 같습니다. def x_ = (y : T) : Unit',하지만 그렇지 않습니다. 후자의 정의로, 나는 setter를 그대로두고 getter 만 오버라이드 할 수있는 권한이있다. var 정의에서는 그렇지 않습니다. –

+3

Hahahahaha, 또 다른 Scala 사양 버그. 산뜻한! – gzm0

+0

@ RégisJean-Gilles 선언은 정의가 아닙니다. –

관련 문제