Re[11]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 19:06
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ВВ>>то это ведь тоже перегрузка.

ARK>Согласен. Хотя вроде бы в окамле операторы разные.

Да, вот только мне лично кажется, что за громкими окамловскими лозунгами "перегрузка есть зло", скрывается банальное убожество недопиленного Хидли-Милнера.
В любом случае есть хороший способ проверить, каково жить без перегрузки, и посмотреть, какие припарки изобретают окамлисты, чтобы все-таки использовать одни и те же имена для разных функций.

ARK>Вообще тут вопрос неоднозначный. Во-первых, в идеальном сферическом языке в вакууме даже оператор сложения не будет перегружен — будет единый тип "число".


Ну каждый второй динамический язык именно такой. Один числовой тип — число. И как-то это не очень удобно.

ARK>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.

ARK>Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


x == y ?

А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?
Re[12]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 19:25
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Вообще тут вопрос неоднозначный. Во-первых, в идеальном сферическом языке в вакууме даже оператор сложения не будет перегружен — будет единый тип "число".


ВВ>Ну каждый второй динамический язык именно такой. Один числовой тип — число. И как-то это не очень удобно.


Скорее всего, там многое не реализовано. Контроля нет за диапазонами чисел, допустимым числом знаков после запятой. Это все должно быть в идеальном языке.

ARK>>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.


Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

ARK>>Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>x == y ?


Ну хорошо, это есть.

ВВ>А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?


Сейчас не готов ответить, я подумаю.
Re[13]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 19:40
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Скорее всего, там многое не реализовано. Контроля нет за диапазонами чисел, допустимым числом знаков после запятой. Это все должно быть в идеальном языке.


И какое число знаков после запятой должно быть допустимо в идеальном языке?

ARK>>>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.

ARK>Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?
Да и кроме математических операторов есть вполне известные всем функции.
Re[12]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 09:09
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ВВ>>>то это ведь тоже перегрузка.

ARK>>Согласен. Хотя вроде бы в окамле операторы разные.

ВВ>Да, вот только мне лично кажется, что за громкими окамловскими лозунгами "перегрузка есть зло", скрывается банальное убожество недопиленного Хидли-Милнера.

ВВ>В любом случае есть хороший способ проверить, каково жить без перегрузки, и посмотреть, какие припарки изобретают окамлисты, чтобы все-таки использовать одни и те же имена для разных функций.

Лично мне не нравится то, что в хаскелеподобных языках нет перегрузки по количеству аргументов в функции. Если ее ввести, то нарушится "лёгкость" карринга и будет путаница. Но можно "утяжелить" запись каррирования функций, т.е. вместо этого:

add x y =  x + y

-- каррируем так:

inc = add 1

-- или так:

map (add 1) [1,2,3]


можно писать так:

add x y =  x + y

-- каррируем так:

inc = add 1 _

-- или так:

map ( add 1 _ ) [1,2,3]

-- и так можно:

map ( _ + 1 ) [1,2,3]

-- или так:

map (it + 1)  [1,2,3]


Имхо, для рядовых смертных так даже понятнее. Возможно будет некая каша, когда подчёркивание "_" есть и слева от равно (в образце при ПМ), так и справа где-то при вызове функции.
Также вероятно, что при разном количестве аргументов Хидли-Милнеру поплохеет. Но зато можно было бы писать так:

add x y =  x + y

inc = add 1 _
inc n = add n _

map inc       [1,2,3]
map (inc 10)  [1,2,3]


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

Я не измучен функциональщиной, лишь изредка покуриваю в эту сторону. Поэтому спрашиваю как человека, познавшего хаскелестроение изнутри. Чем чреват такой "колхоз" в а-ля хаскеле ?
Re[13]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 09:37
Оценка: :)
Здравствуйте, PSV100, Вы писали:

ВВ>>Да, вот только мне лично кажется, что за громкими окамловскими лозунгами "перегрузка есть зло", скрывается банальное убожество недопиленного Хидли-Милнера.

ВВ>>В любом случае есть хороший способ проверить, каково жить без перегрузки, и посмотреть, какие припарки изобретают окамлисты, чтобы все-таки использовать одни и те же имена для разных функций.
PSV>Лично мне не нравится то, что в хаскелеподобных языках нет перегрузки по количеству аргументов в функции. Если ее ввести, то нарушится "лёгкость" карринга и будет путаница. Но можно "утяжелить" запись каррирования функций, т.е. вместо этого:

Variadic functions в той или иной степени сочетаются с каррированием. Посмотри вот, как printf в F# реализован.
А если отключить систему типов, то вполне даже неплохо сочетаются — должна быть только возможность как-либо провести зависимость между аргументами. В той же Ela такое вот прекрасно работает в сочетании с каррированными функциями:

open string

trimChars '!' '?' "!string?"
trimChars '!' "string?"


PSV>Имхо, для рядовых смертных так даже понятнее. Возможно будет некая каша, когда подчёркивание "_" есть и слева от равно (в образце при ПМ), так и справа где-то при вызове функции.


Это не каррирование. Каррирование это представление функции (a->b)->c в a->b->c. В ML/Haskell все функции уже каррированные. Ты же просто описываешь частичное применение на манер Немерле/Скала.
Я бы такое не хотел. Это куча синтаксического мусора и весь поинт-фри пойдет под кат.

PSV>Возможно для той же Ela потребуются некоторые ограничения, например, нельзя нарушать контракт класса, скажем, если в классе определена перегрузка по второму аргументу (или двум первым), то при реализации должно быть минимум два аргумента.


Ну это и сейчас так есть, просто происходит автоматическая эта-экспансия.
Вообще без каррирования та же Ela резко потеряет в выразительности. Каррирование просто означает, что все функции принимают ровно один аргумент, но, так как апликация функции имеет очень высокий приоритет и лево-ассоциативна, то код вида: fun x y полностью аналогичен (fun x) y — т.е. *два* вызова функции вместо одной. Это на самом деле очень удобный трюк. Особенно, если нет необходимости типизировать функцию во время компиляции.

Я ведь, кажется, тебе приводил пример DSL-я:

test1 =
  test "Integer equality"
  given 2
    should be 2
    shouldn't be 33


Где здесь функция, и сколько она аргументов принимает? А если это все с "_" переписать?

PSV>Я не измучен функциональщиной, лишь изредка покуриваю в эту сторону. Поэтому спрашиваю как человека, познавшего хаскелестроение изнутри. Чем чреват такой "колхоз" в а-ля хаскеле ?


Чреват вырезанием combinatory style под корень.
Ну и бесскобочный вызов функций теряет всякий смысл. В общем получится Скала
Re[3]: Зачем нужно наследование интерфейсов?
От: Roman Odaisky Украина  
Дата: 10.07.12 09:53
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Не очень хороший пример, вот если потребуется сделать кликабельный Label... начнут городить огород? Лучше давать возможность добавлять обработку сообщений опционально.


А если потребуется скрестить ужа с ежом? ООП подразумевает незыблемую модель предметной области. Сначала продумать, потом формировать иерархию (вот я не продумывал, я от фонаря привел). Если Label — класс, наследоваться нельзя, и всё. Если есть отдельный интерфейс Captionable { string caption }, то вполне уместно реализовать как его, так и Interactable в некоем классе.

«Сделать кликабельный (интерфейс) Label (класс)» — так задачу ставить нельзя. Добавлять функциональность в завершенные объекты нельзя. Будет нарушен LSP, потому что InteractableLabel is-a Label, но Label is-not-an Interactable. В отличие от интерфейса, контракт класса подразумевает не только реализацию определенных интерфейсов, но также и отсутствие реализации всех остальных (например, на практике это может проявляться в прозрачности для событий, если объект Label загораживает собой кликабельный объект).

Тут возникает другой вопрос, ведь любой класс является сам себе интерфейсом, можно ли наследоваться от этого неявного интерфейса? Наследовать реализацию недопустимо, а вот интерфейс — это вполне укладывается в ООП.
До последнего не верил в пирамиду Лебедева.
Re[4]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 10.07.12 11:58
Оценка:
Какая стена текста... А не проще ли эту кликабельность ака Interactable отделить от рисуемых объектов.? И вообще обработки сообщений делать отдельно, предлагаемый подход неверен.

А то мы заходим для всех рисуемых обрабатывать еще какие-то сообщения, кроме кликов — с таким подходом будете править базовые классы?...
Сало Украине, Героям Сала
Re[5]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 10.07.12 12:02
Оценка:
П.с. я о том что это плохой пример иерархии был дан. И такие примеры часто даются во всяких учебниках... в общем плохо.
Сало Украине, Героям Сала
Re[14]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 13:11
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Variadic functions в той или иной степени сочетаются с каррированием. Посмотри вот, как printf в F# реализован.

ВВ>А если отключить систему типов, то вполне даже неплохо сочетаются — должна быть только возможность как-либо провести зависимость между аргументами. В той же Ela такое вот прекрасно работает в сочетании с каррированными функциями:
ВВ>[...]

ВВ>Это не каррирование. Каррирование это представление функции (a->b)->c в a->b->c. В ML/Haskell все функции уже каррированные. Ты же просто описываешь частичное применение на манер Немерле/Скала.

ВВ>Я бы такое не хотел. Это куча синтаксического мусора и весь поинт-фри пойдет под кат.

ВВ>Вообще без каррирования та же Ela резко потеряет в выразительности. Каррирование просто означает, что все функции принимают ровно один аргумент, но, так как апликация функции имеет очень высокий приоритет и лево-ассоциативна, то код вида: fun x y полностью аналогичен (fun x) y — т.е. *два* вызова функции вместо одной. Это на самом деле очень удобный трюк. Особенно, если нет необходимости типизировать функцию во время компиляции.


ВВ>Я ведь, кажется, тебе приводил пример DSL-я:

ВВ>[...]
ВВ>Где здесь функция, и сколько она аргументов принимает? А если это все с "_" переписать?

ВВ>Чреват вырезанием combinatory style под корень.

ВВ>Ну и бесскобочный вызов функций теряет всякий смысл. В общем получится Скала

Да, я подразумевал именно частичное применение функций, нежели каррирование, как таковое. И как раз навеянное понтами Скалы
Variadic functions как-то вылетели из головы, в Хаскеле их нет, а в Ela опять не доглядел. В общем, с ними жить можно, понятно.

И тогда попутно пару вопросиков, чтобы уже два раза не вставать...

— В Ela есть адаптации вида: "(+) 1 2 3 4" может быть эквивалентно "(+) [1,2,3,4]", если есть "+" для списка, или тупл к списку адаптирован из "(+) 1,2,3,4" или со скобками "(+) (1,2,3,4)". Есть конфликты в синтаксисе в этом случае, или это как-то неправославно ?

— Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

{h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}

Откровенно говоря, хаскелевские скобки "{}" как-то не очень в нём наглядны. Имхо, лучше обычные скобки, вместо "равно" (чтобы не было лишней путаницы) использовать двоеточие :

(h: 14, m: 15, s: 37)

Как раз больше напоминает тупл с именованными полями. Да и неплохо бы скобки опускать, когда можно. В итоге:

time 14h, 15m, 37s
inc (13h, 14m) 12h

или так:

time (14h 15m 37s)
inc (13h 14m) 12h

или более "стандартнее", что ли:

time (14h, 15m, 37s)
inc (13h, 14m) 12h


Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?
Re[14]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 13:14
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Скорее всего, там многое не реализовано. Контроля нет за диапазонами чисел, допустимым числом знаков после запятой. Это все должно быть в идеальном языке.


ВВ>И какое число знаков после запятой должно быть допустимо в идеальном языке?


Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

type Int32 is Number where (value >= 0) and (value <= 2000000000);

function Test(num: Number)
requires
decimal_digits(num) = 3
begin
...

ARK>>>>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>>>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.

ARK>>Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

ВВ>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?


Если числовой тип один, то все будет в одном экземпляре.
Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

ВВ>Да и кроме математических операторов есть вполне известные всем функции.


Например? Читать/писать в поток?

ВВ>А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?


Подумал. Может быть действительно разницы нет. Если что-то в голову придет, напишу.
Re[15]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 13:44
Оценка:
Здравствуйте, PSV100, Вы писали:

PSV>Да, я подразумевал именно частичное применение функций, нежели каррирование, как таковое. И как раз навеянное понтами Скалы

PSV>Variadic functions как-то вылетели из головы, в Хаскеле их нет, а в Ela опять не доглядел. В общем, с ними жить можно, понятно.

Строго говоря, ни в Ela, ни в Хаскелле, никаких variadic функций нет. Но и там, и там они имитируются за счет того, что функции каррированы. В Хаскелле это тоже возможно:
http://rosettacode.org/wiki/Variadic_function#Haskell
В Ela это делать проще, поскольку нет необходимости вычислять функциональный тип.

Наконец, если хочется "перегрузку" по кол-ву аргументов, то ее спокойно можно записать так:

foo (x,y) = ...
foo (x,y,z) = ...
foo (x,y,z,e) = ...

foo (1,2) //Вызываем


В общем практически как в Си. И разница какая?

PSV>И тогда попутно пару вопросиков, чтобы уже два раза не вставать...

PSV>- В Ela есть адаптации вида: "(+) 1 2 3 4" может быть эквивалентно "(+) [1,2,3,4]", если есть "+" для списка, или тупл к списку адаптирован из "(+) 1,2,3,4" или со скобками "(+) (1,2,3,4)". Есть конфликты в синтаксисе в этом случае, или это как-то неправославно ?

Не, ну все же (+) — это бинарная коммутативная операция, и в классе она описана как a->_. Код вида "(+) [1,2,3,4]" частично применит ее и вернет функцию. А когда попробуешь применить эту функцию к какому-нибудь аргументу, то все вылетит, т.к. нет инстанса.
(+) для списков в теории реализовать можно, но это как-то неправильно.

Вообще я, честно говоря, не понимаю, что все это такое. "(+) 1 2 3 4" работать никак не может, т.к. вот здесь "(+) 1 2" вызов будет сатурирован, и далее мы будем пытаться применить целое число как функцию, что, естественно, не сработает.

Ты меня, наверное, неправильно понял. Variadic функций нет. Все функции принимают один аргумент и что-то возвращают. Функции с несколькими аргументами имитируются тем, что одна функция возвращает другую функцию. Например, (+) можно так описать:

sum = \x -> \y -> x+y
sum 2 3


С учетом динамики ты можешь на основе, скажем, значений аргументов определять, нужно ли тебе вернуть функцию, или совершить какое-либо вычисление. Выглядит это как variadic функция, но по сути — это самая обычная нетипизированная лямбда, ничего дополнительного тут нет.

Поэтому все примеры, которые ты привел выше, в Ela не имеют смысла и не работают.

PSV>- Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

PSV> {h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}
PSV>Откровенно говоря, хаскелевские скобки "{}" как-то не очень в нём наглядны. Имхо, лучше обычные скобки, вместо "равно" (чтобы не было лишней путаницы) использовать двоеточие :
PSV> (h: 14, m: 15, s: 37)

Ну для это надо прошивать какие-то литералы. Хотя вот последний пример мало чем отличается от записи:

{h=14,m=15,s=37}


Запятую вообще нельзя использовать как оператор, и по-другому не будет. Запятая — часть синтаксических конструкций, если ее использовать как оператор, все литералы вида [x,y,z] (x,y) сразу станут неоднозначными.

PSV>Как раз больше напоминает тупл с именованными полями. Да и неплохо бы скобки опускать, когда можно. В итоге:

PSV> time 14h, 15m, 37s
PSV> inc (13h, 14m) 12h

Такой синтаксис противоречит всему остальному.

PSV>или так:

PSV> time (14h 15m 37s)
PSV> inc (13h 14m) 12h
PSV>или более "стандартнее", что ли:
PSV> time (14h, 15m, 37s)
PSV> inc (13h, 14m) 12h
PSV>Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?

ИМХО в том, что не имея расширяемых литеральных форм, добавлять синтаксис для каждой единицы измерения — это как-то круто. К тому же в большинстве случаев можно записать практически также, но через функции:

time (hr 14, min 15, sec 37)


Или так:

time Hr 14 Min 15 Sec 37
Re[15]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 13:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>type Int32 is Number where (value >= 0) and (value <= 2000000000);

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

ARK>>>>>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>Если числовой тип один, то все будет в одном экземпляре.
ARK>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

Ну будет та же перегрузка, только в рантайме

ВВ>>Да и кроме математических операторов есть вполне известные всем функции.

ARK>Например? Читать/писать в поток?

Нет, это пример того, как перегрузку использовать не надо.
А вот битовые операции — также вполне известная группа функций.
Re[16]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 16:19
Оценка: :)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>type Int32 is Number where (value >= 0) and (value <= 2000000000);

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


Тут будет не новый тип, а alias — нужно только для того, чтобы не писать эти констрейнты в каждом методе. Тип один — Number.

ARK>>>>>>Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

ВВ>Ну будет та же перегрузка, только в рантайме


Это не перегрузка, а параметрический полиморфизм. Одна функция по сути, пусть и шаблонная. Если конечно придерживаться общепринятых терминов.

ВВ>>>Да и кроме математических операторов есть вполне известные всем функции.

ARK>>Например? Читать/писать в поток?

ВВ>Нет, это пример того, как перегрузку использовать не надо.

ВВ>А вот битовые операции — также вполне известная группа функций.

Битовые операции — опять же проблема только в нескольких числовых типах...
Re[17]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 16:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>>type Int32 is Number where (value >= 0) and (value <= 2000000000);
ВВ>>Мне кажется, ты просто придумал другой способ описывать числовые типы на основе этих констрейнтов.

Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.
К тому же далеко не все так можно выразить. Попробуй так числа Пеано записать.

ВВ>>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.
ВВ>>Ну будет та же перегрузка, только в рантайме
ARK>Это не перегрузка, а параметрический полиморфизм. Одна функция по сути, пусть и шаблонная. Если конечно придерживаться общепринятых терминов.

Ты же написал, что типы должны реализовывать интерфейс Numeric. Соответственно, реализаций будет несколько. Можно сделать один набор статических генерик методов, но они будут работать только благодаря тому, что остальные математические функции перегружены.
И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?
Re[18]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 17:20
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>>>type Int32 is Number where (value >= 0) and (value <= 2000000000);
ВВ>>>Мне кажется, ты просто придумал другой способ описывать числовые типы на основе этих констрейнтов.

ВВ>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.


Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

ВВ>К тому же далеко не все так можно выразить. Попробуй так числа Пеано записать.


В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

ВВ>>>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.
ВВ>>>Ну будет та же перегрузка, только в рантайме
ARK>>Это не перегрузка, а параметрический полиморфизм. Одна функция по сути, пусть и шаблонная. Если конечно придерживаться общепринятых терминов.

ВВ>Ты же написал, что типы должны реализовывать интерфейс Numeric. Соответственно, реализаций будет несколько. Можно сделать один набор статических генерик методов, но они будут работать только благодаря тому, что остальные математические функции перегружены.


А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.

ВВ>И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?


Тут я совсем не копенгаген, беглый обзор википедии не помог. А в чем там сложность?
Re[19]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 17:30
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Здравствуйте, AlexRK, Вы писали:


ВВ>>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.

ARK>Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

Гм, а что тогда такое тип по-твоему?

ВВ>>К тому же далеко не все так можно выразить. Попробуй так числа Пеано записать.

ARK>В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо.

ARK>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.


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

ВВ>>И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?


ARK>Тут я совсем не копенгаген, беглый обзор википедии не помог. А в чем там сложность?
Re[16]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 17:31
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Строго говоря, ни в Ela, ни в Хаскелле, никаких variadic функций нет. Но и там, и там они имитируются за счет того, что функции каррированы. В Хаскелле это тоже возможно:

ВВ>http://rosettacode.org/wiki/Variadic_function#Haskell
ВВ>В Ela это делать проще, поскольку нет необходимости вычислять функциональный тип.

В то, что эффект variadic функций достигается за счёт карринга, я сразу въехал, как только посмотрел примеры в Ela. За ссылку отдельное спасибо, я как раз полез на сайт Хаскеля в надежде найти очередные трюки для борьбы с типами, но не докопался.

ВВ>Наконец, если хочется "перегрузку" по кол-ву аргументов, то ее спокойно можно записать так:

ВВ>[...]
ВВ>В общем практически как в Си. И разница какая?

Но это не совсем то, о чём говорилось. Тут проблема в том, что в Хаскеле всё нужно эмулировать и постоянно бороться с системой типов. В результате плодятся функции вида add, add2, map, mapM, mapM_ и т.п. (хотя выделять "...M" возможно полезно, от греха подальше).

ВВ>Не, ну все же (+) — это бинарная коммутативная операция, и в классе она описана как a->_. Код вида "(+) [1,2,3,4]" частично применит ее и вернет функцию. А когда попробуешь применить эту функцию к какому-нибудь аргументу, то все вылетит, т.к. нет инстанса.

ВВ>(+) для списков в теории реализовать можно, но это как-то неправильно.
ВВ>Вообще я, честно говоря, не понимаю, что все это такое. "(+) 1 2 3 4" работать никак не может, т.к. вот здесь "(+) 1 2" вызов будет сатурирован, и далее мы будем пытаться применить целое число как функцию, что, естественно, не сработает.

Это было предположение, что, если реализовать "плюс" для списка, то есть ли сахар, чтобы (для DSL, например) вместо "(+) [1,2,3,4]" написать "(+) 1 2 3 4". В общем-то, да, торможу, при "variadic функциях" и сахарить не нужно.

PSV>>- Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

PSV>> {h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}
PSV>> [...]
PSV>>Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?

ВВ>[...]

ВВ>ИМХО в том, что не имея расширяемых литеральных форм, добавлять синтаксис для каждой единицы измерения — это как-то круто.

Здесь имелось в виду то, что метки в records можно писать и как единицы измерения, т.е. {kg=28, gr=190} можно также записать как {28kg, 190gr}. Но при:
time (hr 14, min 15, sec 37)
time Hr 14 Min 15 Sec 37

нет смысла морочить голову.

В общем, в голове были сумбурные мысли под впечатлением примерчиков DSL. Всё прояснилось. Спасибо.
Re[20]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 18:34
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>>Здравствуйте, AlexRK, Вы писали:


ВВ>>>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.

ARK>>Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

ВВ>Гм, а что тогда такое тип по-твоему?


Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.

ВВ>>>К тому же далеко не все так можно выразить. Попробуй так числа Пеано записать.

ARK>>В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

ВВ>Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо.


Понятно. Правда, насколько распространены такие задачи... На современных промышленных ЯП такого тоже не сделаешь.

ARK>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.


ВВ>В вычислениях используются различные константы, которые могут иметь разную точность.


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

ВВ>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл.


Наверное тут надо опять работать с предусловиями.
Re[3]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.07.12 21:21
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Нафиг, нужен такой полиморфизм. IPet-ом может быть не только IAnimal, но и IBird, IReptiles, IFish ...


Которые, в свою очередь, являются IAnimal?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[7]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.07.12 21:21
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>Алиасы уже тут обсуждались, не обязательно в каждом месте.


Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?
Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.