2011-09-06 5 views
12

Что я могу использовать модификатор private final в Scala?Использование частного финального модификатора Scala?

Учитывая приведенный ниже код:

1| class A { def callFoo = foo; private final def foo = "bar of A" } 
2| class B extends A { private final def foo = "bar of B"} 
3| println((new A()).callFoo) 
4| println((new B()).callFoo) 

линии 3 и 4 напечатает:

1| bar of A 
2| bar of A 

Вполне понятно, почему линия 2 не печатает bar of B, потому что есть на самом деле два foo определения и последние в B не переопределяет первое в A. В противном случае Scala потребует override - вместо модификатора final.

Почему Scala не просто запрещает комбинацию модификаторов private final?

ответ

14

Хорошо, это сложно. Ваш вопрос: «Почему Scala не просто запрещает сочетание модификаторов частного финала?» основан на предположении, что эта комбинация бесполезна.

Предположим, вы правы (и вы, за исключением крошечной детали, о которой будет сказано ниже). Я не компилятор, но с моей точки зрения «просто запретить», вероятно, не так просто (по крайней мере, в этом случае). И почему кто-то пытается это сделать? Каковы компромиссы? Только потому, что что-то не полезно, не обязательно означает, что он наносит какой-либо вред. Просто не используйте его ...

Теперь вот крошечная деталь, которую вы, кажется, упустили. Модификатор private является модификатором видимости, что означает, что class B не знает о его существовании. Но модификаторы видимости Scala немного сложнее, чем Java. Предположим, что по какой-либо причине вам понадобится код, показанный в следующем фрагменте кода, компилятор не разрешит его.

package scope 

class A { 
    def callFoo = foo; 
    private[scope] final def foo = "bar of A" 
} 
class B extends A { 
    private[scope] final def foo = "bar of B" 
} 

object Main extends App { 
    println((new A()).callFoo) 
    println((new B()).callFoo) 
} 

Это одна из ошибок, предоставляемых компилятором: «метод Foo не может переопределить конечный элемент».

Итак, вы здесь. Scala просто запрещает это сочетание;)

+0

Я не думал о дополнительной области, которую может иметь модификатор. Вы правы, имея конфиденциальное определение пакета, 'final' запрещает его отменять. В этом случае это имеет смысл. Но в противном случае я думаю, что языковая конструкция без эффекта не должна быть законной. Здесь, если 'final' не препятствует переопределению определений подклассов или признаков, то они не должны использоваться в объявлении. –

+0

@ Исследуйте причину, по которой 'final' не предотвращает переопределение подклассов/признаков, переопределяющих определение, потому что' private' уже предотвратил это. 'private' члены не видны для подклассов, поэтому переопределение нечего. Чтобы это было проблемой, вам программисту пришлось бы сделать две различные ошибки: 1) попытка переопределить частный метод и 2) забыть использовать ключевое слово 'override'. Это то же самое в Java, за исключением того, что Java более подвержен ошибкам, поскольку аннотация '@ Override' является необязательной. –

3

Первоначально я думал, что это должно было предотвратить верховные частные методы вложенных классов, но, видимо, не так:

class A { 
    private final def foo = 0 

    class B extends A { 
    override def foo = 1 
    } 
} 

error: method foo overrides nothing 
      override def foo = 1 
         ^

Возможно, это просто упростить рефакторинг? Поэтому, если у вас есть метод final, попробуйте сделать его private, и вам нужно, чтобы он не был private в конце концов, вы не проиграете final ity в процессе?

+1

+1 для «предотвращения плохого рефакторинга»! –

3

Обращаясь к более широкому вопросу,

Так почему же Scala не просто запрещает сочетание модификаторов частных конечных?

Это новое правило и, при этом, новое исключение. Это делает язык более сложным и совершенно не выигрывает. Почему сделать вещи более сложными без уважительной причины?

Это то, что делает Ява, чему Odersky не нравится.Чтобы язык стал более сложным, должен быть некоторый выигрыш.

+2

Язык может стать более сложным для анализатора/компилятора, поскольку он должен знать об этом исключении. Но с точки зрения пользователя я думаю, что легче, когда вы руководствуетесь компилятором. Другим примером может служить «абстрактная черта А» и «черта А». В чем заключается явное указание, что конкретный признак является «абстрактным», если это верно для всех признаков. –

+0

@Tim Вы не считаете нужным для пользователя _learn__whole_ language? В конце концов, это не только компилятор, который должен поддерживать правило - программист должен его изучить. –

Смежные вопросы