Liskov Substitution Principle과 관련이 있습니다. weaker access privileges in subclass (even for Java)을 할당 할 수 없습니다. var
을 def
으로 설정하면 설정자 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 부분 만 무시할 수 있지만 직관적으로 사용자가 var
이 override 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 age
및 def 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에,이 작업을 수행 할 수 없게한다 사실 당신이 할 수있는 사실 :
def는 변경 가능하지 않고, 메소드 정의이기 때문에. SedanCar에서'age = 32'를하면 어떻게되고 싶습니까? –
OP의 질문은 완전히 합리적이라고 생각합니다. 스칼라는 종종 정당한 이유 때문에 균일 액세스 원칙을 준수하는 것으로 제시됩니다. 'age' var 정의를 한 쌍의 getter와 setter ('age'와'age_ =') 메소드의 정의 이상으로 보는 것은 무리가 아닙니다. 어떤 경우에 나는 확실히'age'를 오버라이드 할 수 있어야합니다.'age'는 실제로 getter만을 오버라이드하고 setter는 그대로 둡니다. –