2015-01-29 2 views
3

Черты в Scala могут использоваться как как микшины, так и интерфейсы. Это приводит к некоторой непоследовательности - если я хочу, чтобы закрыть какой-то метод внутри черта, я просто не могу это сделать:инкапсуляция для элементов mixin в Scala

object Library { 
    protected trait A { def a: Int = 5 } 
    trait B extends A { private override def a: Int = super.a } 
    //I want to close `a` memeber for all traits extending B; it's still possible to open it in some another trait `C extends A`, or even `Z extends B with C` 
} 

// Exiting paste mode, now interpreting. 

<console>:10: error: overriding method a in trait A of type => Int; 
method a has weaker access privileges; it should not be private 
      trait B extends A { private override def a: Int = super.a } 
                ^

Такая ошибка совершенно отлично от LSP -perspective как я (или компилятор) может хотеть бросить это супертип A. Но если я просто использую его в качестве микширования, мне никогда не нужно делать это на самом деле, например, в некоторых вариантах Cake-pattern. Я сделаю что-то вроде:

import Library._ 
object O extends B with K with L with App 

и все. Я даже не могу получить доступ к значению A. Я знаю, есть тип вывода, который может перейти к супертипу, но это всего лишь «строка типов», поэтому компилятор мог просто пропустить здесь A и продолжать (конечно, очень теоретично). Другой пример - here Мне пришлось предоставить стандартную реализацию метода, который мне действительно не нужен.

В настоящее время я использую OOP-состав, но он не настолько гибкий (поскольку линеаризация здесь не работает) и не очень совместима с концепцией mix-ins. Некоторые проекты, которые я видел, на самом деле делают mixins и имеют «over9000» redundand visible members. Несколько лет назад появилась идея «маркировать» такой состав mixins на with ключевое слово, заданное вместо extends, но даже не могу найти этот поток сейчас.

Итак, есть ли какие-либо улучшения для инкапсуляции ad-hoc-членов?

ответ

1

Это не общее решение, но это можно закрыть методы от внешнего мира внутри одного модуля:

object Library { 
    protected trait A { 
    private[Library] def a: Int = 5 
    private[Library] def b: Int = 7 
    } 
    trait B extends A { 
    def b = super.b 
    } 
} 

import Library._ 
object C extends B 

scala> C.a 
<console>:179: error: method a in trait B cannot be accessed in object C 
       C.a 
       ^
scala> C.b 
res131: Int = 7 

Таким образом, мы просто перевернув инкапсуляцию здесь. Если A также должны быть открыты для расширения:

object Library { 
    protected trait _A { 
    private[Library] def a: Int = 5 
    private[Library] def b: Int = 7 
    } 
    trait B extends A { /*...*/ } 
    trait A extends _A { 
    override def a = super.a 
    override def b = super.b 
    } 
} 

Так, может быть, слишком шаблонный, но, по крайней мере, это работает.

P.S. Идея частично вдохновлена ​​другим удаленным ответом, который не работал :)