Re[4]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:06
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>Или у кого-то хватило ума добавить туплы без поддержки паттерн-матчинга,


VD>У Майкрософт. Ты тему то прочел?


В этот раз нет. Но раз все действительно так — то и говорить не о чем.
Re[3]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:09
Оценка: +2
Здравствуйте, VladD2, Вы писали:

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


G>>А что можно понять, глядя на вызов такой функции?


G>>res = fun( x, y, z );


G>>?


VD>В таком виде конечно разницы никакой, так как функция (и скорее всего ее параметры) названа в худших традициях функциональщиков.


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

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

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

Разница только в четком отделении output параметров от input. И все. Это — удобно. И это, кстати, главная и по сути единственная штука, которая меня постоянно напрягала при программировании на С++, после знакомства с ФЯ. Остальное можно пережить легко, если уметь обращаться с С++. Но эта мелочь — бесит.
Re[3]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:12
Оценка: :)
Здравствуйте, VladD2, Вы писали:

Что, Влад, спорим в этот раз, чтобы поддержать традицию? Повода нет имхо . Но я не против .
Re[3]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:22
Оценка: +2
Здравствуйте, Andrei N.Sobchuck, Вы писали:

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



G>>Type fun( Type &, Type, Type & )

G>>( res, x, z ) = fun( y );

ANS>Разница между 1 и 2 в том, что точек присваивания много, и в каждом будут свои имена, а точка реализации функции одна.


Что? Не понял, видать тупой стал. Для начала, не то ты зацитировал для сравнения. Правильно:

G>> res = fun( x, y, z );

G>>( res, x, z ) = fun( y );

Вопрос. В каком из вариантов тебе при чтении кода вызова (не точки реализации, которая в обоих случаях одна), тебе проще понять, что входной параметр, что — выходной, а что является побочным эффектом?

Ответ. Капитан очевидность сообщает — во втором варианте выходные параметры нельзя спутать с аргументами с побочными эффектами. Почему это важно, и имеет значение? Капитан очевидность ничего не может на это ответить, кроме сказать, что такой код читать существенно проще. А чтобы понять, почему так — надо уже мозг включать, или иметь опыт поддержки.
Re[4]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.10.09 21:41
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Интересное соображение. А почему ты считаешь, что интеллисенс не сможет показать тебе типов возвращаемого тупла, которые точно так же являются частью сигнатуры функции, интересно?


Потому что у полей нет имен.

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


С типом проблем нет. Но что за толк от знания, что, скажем, функция CalcSome возвращает тип int * int * int?

G>Разница только в четком отделении output параметров от input. И все. Это — удобно.


А я с этим и не спорю. Кортыжу удобнее out/ref-параметров. Но это другой вопрос не устраняющий наличие проблемы потери информации.

G>И это, кстати, главная и по сути единственная штука, которая меня постоянно напрягала при программировании на С++, после знакомства с ФЯ. Остальное можно пережить легко, если уметь обращаться с С++. Но эта мелочь — бесит.


Везет тебе. Меня больше непрягает то, что за памятю нужно следить, выполнять разные дурацкие ретуальные действия и соблюдать кодекс чести только чтобы случайно не нажить себе проблем на пару вечеров.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.10.09 21:45
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

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


G>Что, Влад, спорим в этот раз, чтобы поддержать традицию? Повода нет имхо . Но я не против .


Я собственно не спорю, а указываю на то что проблема очевидно есть. А с тем что тут товарищи, к ним не привыкшие, делаю из мухи слона я не спорю.

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

Кстати, очень помогают локальные функции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:53
Оценка:
Здравствуйте, VladD2, Вы писали:

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


G>>Интересное соображение. А почему ты считаешь, что интеллисенс не сможет показать тебе типов возвращаемого тупла, которые точно так же являются частью сигнатуры функции, интересно?


VD>Потому что у полей нет имен.


Зато всегда есть имена принимающих переменных, которые названы так, что все понятно. Этого мало? Кроме того, это имеет вообще значение только в случае, если возвращаемые значения тупла одного типа. Такое бывает редко, и обычно однозначно трактуется, скажем:

Прямоугольник, или линия — ( x1, y1, x2, y2 ).

Диапазон времени — ( startTime, endTime ).

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

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


VD>С типом проблем нет. Но что за толк от знания, что, скажем, функция CalcSome возвращает тип int * int * int?


Имена принимающих переменных в строке вызова — забыл, нет? На них смотреть религия не позволяет?

G>>Разница только в четком отделении output параметров от input. И все. Это — удобно.


VD>А я с этим и не спорю. Кортыжу удобнее out/ref-параметров. Но это другой вопрос не устраняющий наличие проблемы потери информации.


Существенно большая проблема — что ты не можешь понять, где у тебя output параметр, пока не заглянут в вызывающую функцию. Мешает читать код. Сильно мешает.

G>>И это, кстати, главная и по сути единственная штука, которая меня постоянно напрягала при программировании на С++, после знакомства с ФЯ. Остальное можно пережить легко, если уметь обращаться с С++. Но эта мелочь — бесит.


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


Меня это не напрягало — я придерживался простой но строгой ownership policy, и не имел никаких проблем с ликами. Вообще. Могу рассказать, если интересно.
Re[4]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.10.09 21:55
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>>> res = fun( x, y, z );

G>>>( res, x, z ) = fun( y );

G>Вопрос. В каком из вариантов тебе при чтении кода вызова (не точки реализации, которая в обоих случаях одна), тебе проще понять, что входной параметр, что — выходной, а что является побочным эффектом?


Он имел в виду, что функцию ты описываешь один раз и если накосячил с именами параметров, то только в ней. А вызваешь ты ее 100 раз и накосячить с именами можешь неограниченно количество раз:

def (res, x, z) = fun( y );
...
def (x, res, z) = fun( y );
def (res, x, z) = fun( y );


На практике (на моей) это не часто приводит к проблема. Но потенциальная опасность есть. Шарповские анонимные типы решают эту проблему, но к сожалению у Майкрософт в последнее время огромные проблемы с последовательностью. По сути анонимные типы — это записи (кортежи с именованными полями). Если CLR умел их поддерживать, то достаточно было бы придумать красивый синтаксис описания анонимного типа (что-то вроде описания списка параметров метода, например), то проблема бы и не возникла. Но в МС почитали, что ради такой фигни как стройность флагманского языка менять CLR не стоит. Добавили, правда, что когда будут менять CLR, то исправят ситуацию. 4-й фрэймворк как раз и есть изменение CLR, но практически 100%, что и в нем не появится поддержки анонимных типов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 21:56
Оценка: 57 (2)
Здравствуйте, VladD2, Вы писали:

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


VD>Кстати, очень помогают локальные функции.


Все правильно говоришь, я делаю так же. Кстати, кортежи из 5 элементов не проблема, если ( x, y, ( z, a, b ) ). Кортеж в третьем элементе надо разматчить там, где он реально нужен. И все. Читабельность — сильно выигрывает.

Всяко лучше, чем функция с 5 аргументами, согласись. Опять же — имеем плюс от кортежей в читабельности.
Re[6]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.10.09 22:09
Оценка: +2
Здравствуйте, Gaperton, Вы писали:

G>Зато всегда есть имена принимающих переменных, которые названы так, что все понятно. Этого мало?


Вопрос философский. Для кода реализации метода может и нормально. А в публичном интерфейсе я бы с удовольствием "запечатлел" бы имена и заставил бы компилятор контролировать их соответствие.

В общем, это место где может появиться ошибка и его было бы не так уж трудно устранить. Но... про "но" я написал в соседней ветке.

G>Кроме того, это имеет вообще значение только в случае, если возвращаемые значения тупла одного типа. Такое бывает редко, и обычно однозначно трактуется, скажем:


G>Прямоугольник, или линия — ( x1, y1, x2, y2 ).


Для прямоуголника я бы предпочел не котреж, а структуру с именами полей. А то кто знает, что ты там имел в виду "x2, y2" или "w, h"?

G>Чаще всего, в реальном дизайне даже для этих вещей заводят отдельных тип. Для возвращаемых значений функций — нет. Заводить для них специальный тип — глупость.


Не такая это и глупость. Особенно если тип можно было бы описать по месту.
Что ты имеешь против такого синтаксиса:
GetPersonInfo(id : int) : (Name:string * Addres:string * Age:int)

Ну, а дальше хочешь к полям обращайся через точку:

def p = GetPersonInfo(123);
... p.Age;

или декомпозицию в переменные делай, но чтобы при этом провлялись имена без учета регистра и наличия подчеркиваний в именах:
def (name, _, age) = GetPersonInfo(123); // OK
def (_, name, age) = GetPersonInfo(123); // Error

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

G>Имена принимающих переменных в строке вызова — забыл, нет? На них смотреть религия не позволяет?


Они могут быть перепутаны.

G>Существенно большая проблема — что ты не можешь понять, где у тебя output параметр, пока не заглянут в вызывающую функцию. Мешает читать код. Сильно мешает.


Этой проблемы нет во многих языка:
GetPersonInfo(out name, out addres, out age);

c# к ним относится.

G>Меня это не напрягало — я придерживался простой но строгой ownership policy, и не имел никаких проблем с ликами. Вообще. Могу рассказать, если интересно.


Вот это я и называю "дурацкие ретуальные действия и соблюдать кодекс чести". Проблем и я не имел, но тратил на это время которое мог бы потратить более интересно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 22:28
Оценка:
Здравствуйте, VladD2, Вы писали:

G>>Зато всегда есть имена принимающих переменных, которые названы так, что все понятно. Этого мало?


VD>Вопрос философский. Для кода реализации метода может и нормально. А в публичном интерфейсе я бы с удовольствием "запечатлел" бы имена и заставил бы компилятор контролировать их соответствие.


Я не говорю, что надо употреблять туплы в публично интерфейсе. Стилевое руководство Эрланга рекомендует применять в данном случае record-ы. Это важно, по причине, что на Эрланге написано больше всего промышленного кода с туплами на данный момент — наибольшая практика. Однако, возвращять туплы из пар элементов в публичном интерфейсе, к примеру:

{ Key, Value }

Считается вполне нормальным. И это правильно.

VD>В общем, это место где может появиться ошибка и его было бы не так уж трудно устранить. Но... про "но" я написал в соседней ветке.


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

G>>Кроме того, это имеет вообще значение только в случае, если возвращаемые значения тупла одного типа. Такое бывает редко, и обычно однозначно трактуется, скажем:


G>>Прямоугольник, или линия — ( x1, y1, x2, y2 ).


VD>Для прямоуголника я бы предпочел не котреж, а структуру с именами полей. А то кто знает, что ты там имел в виду "x2, y2" или "w, h"?


G>>Чаще всего, в реальном дизайне даже для этих вещей заводят отдельных тип. Для возвращаемых значений функций — нет. Заводить для них специальный тип — глупость.


VD>Не такая это и глупость. Особенно если тип можно было бы описать по месту.


Смысл какой, если этот тип часть сигнатуры функции, а имена переменных повторяют названия типов? Лишняя писанина.

VD>Что ты имеешь против такого синтаксиса:

VD>
VD>GetPersonInfo(id : int) : (Name:string * Addres:string * Age:int)
VD>

VD>Ну, а дальше хочешь к полям обращайся через точку:

Ничего, если имена опциональны, и меня не заставляют их всегда писать. Хороший синтаксис, помогает при длинных туплах. Я бы сказал, я хочу такой синтаксис, он мне нравится, он крут.

G>>Имена принимающих переменных в строке вызова — забыл, нет? На них смотреть религия не позволяет?


VD>Они могут быть перепутаны.


Ситуация, когда в тупле значения одного типа идут подряд, их много, и они не имеют натурального порядка — крайне редка. Я ни разу с такой багой не сталкивался. Натуральный порядок, например — обозначение временного диапазона — сначала ты пишешь startTime, потом endTime, и по названиям легко понять, что ты их перепутал.

G>>Существенно большая проблема — что ты не можешь понять, где у тебя output параметр, пока не заглянут в вызывающую функцию. Мешает читать код. Сильно мешает.


VD>Этой проблемы нет во многих языка:

VD>
VD>GetPersonInfo(out name, out addres, out age);
VD>

VD>c# к ним относится.

Я не хочу тыкать в каждый вызов, и смотреть его сигнатуру, чтобы понять, что к чему. Это мешает. Я хочу читать код по диагонали — при поддержке это важно. Проблема в С# есть. В С++, к сведению, по кодстандарту CQG ты пишешь в имени аргумента префикс o_, i_, а также io_, что точно так же как и в твоем примере про C# "исправляет" ситуацию. Но я не хочу смотреть в сигнатуру. Вариант с туплами объективно лучше этих костылей во всех смыслах, не понимаю, с чем ты споришь. Это очевидно.

G>>Меня это не напрягало — я придерживался простой но строгой ownership policy, и не имел никаких проблем с ликами. Вообще. Могу рассказать, если интересно.


VD>Вот это я и называю "дурацкие ретуальные действия и соблюдать кодекс чести". Проблем и я не имел, но тратил на это время которое мог бы потратить более интересно.


Я не тратил на это много времени. Один шаблонный класс MemberPtr для агрегации по указателю, который копирует контент при присваиваниях и конструкторе копирования, и удаляет в деструкторе — и все, никаких трат времени. Заодно — глядя на объявление класса, легко видно, где просто ссылка, а где агрегация. И никакого геморроя и потраченного времени.
Re[5]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 09.10.09 22:32
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


G>>>> res = fun( x, y, z );

G>>>>( res, x, z ) = fun( y );

G>>Вопрос. В каком из вариантов тебе при чтении кода вызова (не точки реализации, которая в обоих случаях одна), тебе проще понять, что входной параметр, что — выходной, а что является побочным эффектом?


VD>Он имел в виду, что функцию ты описываешь один раз и если накосячил с именами параметров, то только в ней. А вызваешь ты ее 100 раз и накосячить с именами можешь неограниченно количество раз:


VD>
VD>def (res, x, z) = fun( y );
VD>...
VD>def (x, res, z) = fun( y );
VD>def (res, x, z) = fun( y );
VD>


Да ну. А без туплов, типа, ты не можешь 100 раз накосячить так:

VD>
VD> res = fun( y, x, z );
VD>...
VD> x = fun( y, res, z );
VD> res = fun( x, z, y );
VD>


Разница — в чем? Вы о чем вообще говорите, люди? Бред какой-то.

VD>На практике (на моей) это не часто приводит к проблема. Но потенциальная опасность есть.


На моей практике это ни разу не приводило к большим проблемам, чем опасность перепутать порядок аргументов функции. Разницы — никакой. Вообще. Кроме пользы.
Re[6]: Использование tuple
От: maxkar  
Дата: 10.10.09 06:46
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


VD>>>Например, кому не ясно значение следующего метода list[T]?

VD>>>
VD>>>    public Partition (pred : T -> bool) : list [T] * list [T] 
VD>>>


M>>Мне не ясно, например. Кто первый в этой паре?


VD>Бывает. Наверно в школе с учебниками математики тоже проблемы были?

Да нет, с учебниками проблем не было. Особенно с учебниками математики. Я по ней олимпиадник был и пару раз участвовал в отборах на международный этап
С учебниками в общем случае чуть проще — там вроде бы практически все функции возвращают одно значение (одного "типа", а не в смысле однозначная/многозначная функция). Да и функций от двух и более аргументов вроде бы не слишком много. Т.е. подобных проблем нет.

M>> То, что соответствует предикату или то, что не соответствует?


VD>Разумеется сначала идут те что соответствуют, потом те что не соответствуют.


Почему разумеется? Вот есть у нас список [1,2,3,4,5,6]. И есть какой-то предикат p. Как разделять будем? Да очень просто — читаем список слева направо и все, на что p дает true, вычеркиваем и записываем в другой спискок. Ну и получим в результате что-то вроде [1,2,5][3,4,6]. Ну так здесь первое — это то, что фильтру не соответствуют. И "логических ошибок" я здесь не вижу. Да, вопросы "зачем так делать" есть, но противоречий показать не получится. В результате у кого-то из читающих могут возникнуть проблемы. И на больших командах вероятность неправильного понимания хотя бы у одного члена возрастает. Учитывая, что большинство программистов читать документацию не любит и то, что многие даже не "тестируют простейшие случаи", мы получим место для бага.

M>>И, самое интересное. Как я должен рассуждать, чтобы получить "правильный" ответ? Документацию я специально не смотрел и на шарпе не пишу.


VD>А как ты рассуждаешь когда используешь функцию Filter или Where? А в друг результат будет обратный предикату?


Вот если я использую Where, то рассуждаю просто — collection.where(predicate). Очевидно, это "коллекция", "где" выполняется "предикат". А с фильтром я не рассуждаю, я смотрю (или вспоминаю) документацию. Как раз потому, что не понятно, что именно должно вернуть colleciton.filter(predicate). И если посмотреть словари английского языка (я смотрел и переводы, и толковые словари), выяснится, что "filter something" имеет значение "remove something". Еще видел определение "pass through filter", но там в определении существительного "filter" тоже было "to remove". И вот здесь то как раз огромное место для путаницы, что определяет предикат — то, что нужно "отфильтровать", или то, что получить в результате.

VD>В реальном коде все выглядеть примерно так:

VD>
VD>def (fresh, old) = data.Partition(x => x.DateTime.Year >= DateTime.Now.Year);
VD>...
VD>

Угу. И если мне такой код попадется на review, я как раз пойду смотреть, в каком же порядке data.Partition() возвращает результат. Потому что по вышеописанным причинам здесь у писателя может быть ход мысли, отличный от хода мысли автора функции. Вообще, это проблема в первую очередь для прикладного кода, а не для библиотек. Библиотек все же не так много и их приходится знать (т.е. я буду помнить, что же делает библиотечный partition). А вот запоминать кучу дополнительных контрактов для "прикладного" кода ну совсем не хочется.

P.S. И вне зависимости от контракта метода data.Partition, я бы не оставил последний пример в коде в том виде, в котором он есть. Скорее всего, это было бы гневное письмо к автору с вопросом о том, что же именно делает эта строчка кода. Потому что в old могут оказаться x, у которых datetime идут раньше (не позже), чем у некоторых x из fresh. И что самое обидное, этот баг будет проявляться на новый год (когда DateTime.Now.Year изменится во время вычисления Partition). А мне ну никак не хочется быть выдернутым в новогоднюю ночь фиксить критический баг. Да и в новогодние каникулы тоже не хочется.
Re[8]: Использование tuple
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.10.09 07:44
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Я не хочу тыкать в каждый вызов, и смотреть его сигнатуру, чтобы понять, что к чему. Это мешает. Я хочу читать код по диагонали — при поддержке это важно. Проблема в С# есть. В С++, к сведению, по кодстандарту CQG ты пишешь в имени аргумента префикс o_, i_, а также io_, что точно так же как и в твоем примере про C# "исправляет" ситуацию. Но я не хочу смотреть в сигнатуру.


Ты не понял — в шарпе out указывается и при вызове тоже.
... << RSDN@Home 1.2.0 alpha 4 rev. 1245 on Windows 7 6.1.7600.0>>
AVK Blog
Re[8]: Использование tuple
От: Mirrorer  
Дата: 10.10.09 07:56
Оценка:
Здравствуйте, Gaperton, Вы писали:


G>Я не говорю, что надо употреблять туплы в публично интерфейсе. Стилевое руководство Эрланга рекомендует применять в данном случае record-ы.


Имеется ввиду эта штука или что-то другое ?
Re[8]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.10.09 11:59
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Ситуация, когда в тупле значения одного типа идут подряд, их много, и они не имеют натурального порядка — крайне редка. Я ни разу с такой багой не сталкивался. Натуральный порядок, например — обозначение временного диапазона — сначала ты пишешь startTime, потом endTime, и по названиям легко понять, что ты их перепутал.


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

G>Я не хочу тыкать в каждый вызов, и смотреть его сигнатуру, чтобы понять, что к чему. Это мешает. Я хочу читать код по диагонали — при поддержке это важно. Проблема в С# есть. В С++, к сведению, по кодстандарту CQG ты пишешь в имени аргумента префикс o_, i_, а также io_, что точно так же как и в твоем примере про C# "исправляет" ситуацию. Но я не хочу смотреть в сигнатуру. Вариант с туплами объективно лучше этих костылей во всех смыслах, не понимаю, с чем ты споришь. Это очевидно.


Ты не понял. Язык заставляет писать out/ref при вызове. Если в функции есть out-параметр, то ты не можешь не написать при вызове "out variable", так как в противном случае компилятор выдаст ошибку. Сделано это как раз, чтобы сразу было понятно, что параметр возвращает значение.

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

VD>>Вот это я и называю "дурацкие ретуальные действия и соблюдать кодекс чести". Проблем и я не имел, но тратил на это время которое мог бы потратить более интересно.


G>Я не тратил на это много времени.


А вот это, извини за резкость, сказки. Иначе скорость программирования на любом языке была бы одинакова, так как ко всему можно привыкнуть и "не иметь проблем".

G>Один шаблонный класс MemberPtr для агрегации по указателю, который копирует контент при присваиваниях и конструкторе копирования, и удаляет в деструкторе — и все, никаких трат времени. Заодно — глядя на объявление класса, легко видно, где просто ссылка, а где агрегация. И никакого геморроя и потраченного времени.


Не, батенька. Время ты тратишь при проектировании. Ты вынужден создавать более детальные решения. Вынужден продумывать иделогию владения и т.п. Плюс ты вынужден заниматься ритуальными приседаниями.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.10.09 12:11
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

G>Да ну. А без туплов, типа, ты не можешь 100 раз накосячить так:


VD>>
VD>> res = fun( y, x, z );
VD>>...
VD>> x = fun( y, res, z );
VD>> res = fun( x, z, y );
VD>>


Могу. Но разобраться будте проще. Так как мне будте достаточно поглядеть на хинт в IDE и увидить несоответствие.

G>Разница — в чем? Вы о чем вообще говорите, люди? Бред какой-то.


Мы говорим о статически типизированных языках имющих офигительную поддержку IDE. Она в сочетании с языковыми решениями позволяет делать меньше ошибок. Тюплы тут несколько не вписываются в картину. Еще раз повторюсь, что лично мне, хотя я крайне неаккуратный человек, это не очень мешает, но я уверен, что если мы говорим о действительном массовом применении, то это не самое лучше решение которое будет источником ошибок. Другое дело, что применение циклов, к примеру, не чем не меньший источник ошибок. Но люди к ним привыкли и не обращают на это внимание. А на кортежи обращают, так как вещь новая, а все новые вещи у разумных людей, по началу взывают опасения.

Так вот замена (точнее дополнение к) циклам — ФВП. Таким же дополнением к кортежам должны быть записи.
Ты сам говоришь, что в эрланге есть записи и их рекомендуется экспортировать из публичных функций.
А вот в дотнете (заметь, не шарпе, а именно дотнете) нет аналога записей. Конечно можно объявить класс, но вот беда, класс не будет идентичен такому же классу объявленному другой сборке. К тому же класс нужно явно объявлять, а в шарпе — это требует написания довольно большого объема кода (конструкторы нужно описывать, права доступа задавать...), что неудобно. Отличным решением было бы ввести в дотнет записи. Тогда в языке можно было бы ввести инлайн-синтаксис описания этих самых записей и многие проблемы ушли бы сами собой.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.10.09 12:24
Оценка: +1 -1
Здравствуйте, maxkar, Вы писали:

M>Да нет, с учебниками проблем не было. Особенно с учебниками математики. Я по ней олимпиадник был и пару раз участвовал в отборах на международный этап


Вот и тут не будет. У тебя же не бывает проблем с чтение кода вроде "f(a, b)"? Ну, и с "def (a, b) = f();" не будет.

M>Почему разумеется?


Потому что это интуитивно. Везде в ФЯ ты будешь встречать конструкции вроде "head :: tail". Так что о том, что идет вначале ты даже задумываться не будешь. А если вдруг задумаешся, то есть описание метода доступное как в коментариях, так и в интеллисенсе (в IDE).

M>Вот есть у нас список [1,2,3,4,5,6]. И есть какой-то предикат p. Как разделять будем? Да очень просто — читаем список слева направо и все, на что p дает true, вычеркиваем и записываем в другой спискок.


Это какая-то извращенная императивная логика. Функциональная логика будет такая:
1. Для пустого списаа [] вернем ([], []).
2. Для не пустого списка x :: xs присоединим x к первому списку если x удовлетворяет предикату и ко второму если нет.
3. Повторим рекурсивно операцию для остатка списка (xs).
А вот как эта реализация записана на немерле:
    /**
     * Partitions a list into two sublists according to a predicate.
     */
    public Partition[T] (l : list [T], pred : T -> bool) : list [T] * list [T]
    {
      def loop (l : list [T], sat : list [T], notsat : list [T])
      {
        match (l) {
          | h :: t => 
            if (pred (h)) 
              loop (t, h :: sat, notsat)
            else 
              loop (t, sat, h :: notsat)
          | [] => (Rev (sat), Rev (notsat))
        }
      }
      loop (l, [], [])  
    }


M>Вот если я использую Where, то рассуждаю просто — collection.where(predicate). Очевидно, это "коллекция", "где" выполняется "предикат". А с фильтром я не рассуждаю,


А, ну, ясно решил докопаться до радио. Продолжай в том же духе.
Методом Select не пользуйся, так как до него тоже можно докапываться. Он же занимается отображением или проекциец, а не как не выбором. SQL тоже в плохиши запиши...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Использование tuple
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.10.09 12:34
Оценка: :)
Здравствуйте, maxkar, Вы писали:

VD>>А как ты рассуждаешь когда используешь функцию Filter или Where? А в друг результат будет обратный предикату?


M>Вот если я использую Where, то рассуждаю просто — collection.where(predicate). Очевидно, это "коллекция", "где" выполняется "предикат". А с фильтром я не рассуждаю, я смотрю (или вспоминаю) документацию. Как раз потому, что не понятно, что именно должно вернуть colleciton.filter(predicate). И если посмотреть словари английского языка (я смотрел и переводы, и толковые словари), выяснится, что "filter something" имеет значение "remove something". Еще видел определение "pass through filter", но там в определении существительного "filter" тоже было "to remove". И вот здесь то как раз огромное место для путаницы, что определяет предикат — то, что нужно "отфильтровать", или то, что получить в результате.


VD>>В реальном коде все выглядеть примерно так:

VD>>
VD>>def (fresh, old) = data.Partition(x => x.DateTime.Year >= DateTime.Now.Year);
VD>>...
VD>>

M>Угу. И если мне такой код попадется на review, я как раз пойду смотреть, в каком же порядке data.Partition() возвращает результат.

На самом деле программист обязан знать, что делает функция или метод, так как они являются абстракцией. Вопрос в том, что какие-то функции могут получить интуитивные имена, а какие-то нет (не будем же мы давать функциям имена состоящие из 40 слов?). И это не зависит от того используются ли тюплы или нет. Ты точно так же поцдешь смотреть, что делает функция если она возвратит одно значение. Да что там одно? Даже если она вообще ничего не возвращает, ты можешь "пойти". Ну, а вопрос интуитивности это совершенно отдельный вопрос. Для меня Filter и Partition совершенно интуитивно понятные названия определяющие как параметры, так и вовращаемые значения. Если тебе они не ясны, ну, что что или запомнишь, или будешь каждый раз читать документацию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Использование tuple
От: Gaperton http://gaperton.livejournal.com
Дата: 11.10.09 14:06
Оценка:
Здравствуйте, AndrewVK, Вы писали:

G>>Я не хочу тыкать в каждый вызов, и смотреть его сигнатуру, чтобы понять, что к чему. Это мешает. Я хочу читать код по диагонали — при поддержке это важно. Проблема в С# есть. В С++, к сведению, по кодстандарту CQG ты пишешь в имени аргумента префикс o_, i_, а также io_, что точно так же как и в твоем примере про C# "исправляет" ситуацию. Но я не хочу смотреть в сигнатуру.


AVK>Ты не понял — в шарпе out указывается и при вызове тоже.


Это несколько меняет дело. Но только "несколько". Как это поможет мне отличить выходной параметр от параметра io_ — с побочным эффектом? Туплы решают именно эту проблему. Кроме того, с туплами это выглядит элементарно лучше и естественнее, чем префиксы. Разумеется, при поддержке паттерн-матчинга на них.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.