2011-03-28 6 views
6

Я только что начал изучать Scala. Я достаточно доволен дизайном OO, а тем более с функциональным программированием; хотя, я программировал достаточно долго, чтобы FP не совсем неестественна для меня. С первого дня моего приключения в Скале у меня было это, скажем так, неудобство с очевидной диалектикой, которая происходит между OO и FP. Ясно, что каждый может идти так или иначе. Моя первая тенденция заключалась в том, чтобы рассматривать классы как свои пакеты, которые объединяют функции, которые я хочу передать, что уравновешивает шкалы по функциональной стороне. Я чувствую, что должен быть лучший способ сбалансировать действие. Я также не уверен, как приступить к некоторым знакомым ситуациям в рамках этого сценария. Например, если у меня был следующий (искусственный) класс:Scala Function vs Class Dichotomy

class ValueGenerator { 
    def value() = { 
     "1" 
    } 
    def value(line: String) = { 
     line 
    } 
} 

в ОО программирования я бы назвал value с соответствующей подписью, когда мне нужно, чтобы получить результат, что мне нужно. Методы имеют одинаковую подпись, поскольку они логически соответствуют аналогичным действиям. В OO я передал бы ссылку на объект, и методы, которые получают объект ValueGenerator, сделают звонок справа value в зависимости от ситуации. Насколько я вижу, по крайней мере, это моя тенденция, что в Скале норма должна пройти вокруг метода. Но в этом случае, хотя методы делают то же самое, у них нет одинаковой сигнатуры, поэтому они не могут быть заменены друг на друга (или они могут?). Другими словами, может ли метод отправителя решить, какую функцию нужно отправить независимо от подписи функции? Это кажется маловероятным, поскольку получатель не знает, как его вызывать. Какое правильное действие в такой ситуации. Или один идет с инстинктом кишки? Есть ли эмпирическое правило, которое вы придерживаетесь, когда дело доходит до OO vs FB?

В качестве примечания было интересно видеть, что мой друг, который также изучает Скала, имел точные мысли (или их отсутствие), как я по этому вопросу.

+2

Методы не имеют одинаковой сигнатуры: один принимает один аргумент типа String, другой не принимает аргументов. Из раздела 2.10.2 спецификации JVM: «Подпись метода состоит из имени метода, количества и типа формальных параметров (§2.10.1) метода [...]» –

+0

Кроме того, вы должен заметить, что метод - это что-то, функция - это что-то другое. Вы не проходите мимо методов, вы можете передавать только функции. Вы можете, однако, поднять метод в функцию. –

+0

См. Также http://jim-mcbeath.blogspot.com/2009/05/scala-functions-vs-methods.html –

ответ

4

В коде вы при условии, что нет никаких причин, вы должны иметь две отдельные сигнатуры метода:

class ValueGenerator { 
    def value(line: String = "1") = { 
    line 
    } 
} 

REPL сессия:

scala> new ValueGenerator() 
res1: ValueGenerator = [email protected] 

scala> res1.value("Foo") 
res2: String = Foo 

scala> res1.value() 
res3: String = 1 

Имейте в виду, вы можете сделать это только с методами. Функции не поддерживают аргументы по умолчанию:

scala> val f = res1.value(_) 
f: (String) => String = <function1> 

scala> f("Bar") 
res5: String = Bar 

scala> f() 
***Oops*** 

scala> val f = (line: String) => line  
f: (String) => String = <function1> 

scala> val f = (line: String = "1") => line 
***Oops*** 
9

У них нет такой же подписи, и обычно вам нужны методы, у которых нет одинаковой подписи с разными именами. Перегрузка покупает вас очень мало и дорого стоит (а именно, тип вывода и неявное разрешение).

Таким образом, они не могут подставляться друг другу, так как они не имеют одного и того же типа. Если бы вы преобразовали эти методы в функции, у вас был бы тип Function0[String], а у другого был бы тип Function1[String, String].

2

Насколько я вижу, по крайней мере, это моя тенденция, что в Scala норма должна проходить вокруг метода.

Я сомневаюсь, что это норма (почему вы так считаете?) Или что в Scala есть вообще норма для этого.

Но в этом случае, хотя методы делают то же самое, они не имеют одинаковой сигнатуры, поэтому не могут быть заменены друг на друга (или они могут?). Другими словами, может ли метод отправителя решить, какую функцию нужно отправить независимо от подписи функции?

Их нельзя заменить друг на друга, поскольку они имеют разные подписи, поэтому у них разные типы.

Сценарий, который вы описываете, звучит как идеально подходящий для способа OO: просто передайте объект ValueGenerator и позвольте клиенту решить, какой метод вызывать в этом объекте.

+0

Ну, я не знаю, что такое норма, но есть образцы дизайна и лучшие практики для любой данный язык и время, когда все языки имеют тенденцию к слабому сближению при таком использовании. Например, в этом случае я мог бы сделать это способом OO, но я мог бы также хранить 'line' в классе и иметь только один метод для' value', который я могу обойти, чтобы справиться с ним. Два разных подхода к достижению одного и того же. – delmet