Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.

Кэр>>Такой return
VD>>>
VD>>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>>

Кэр>>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

K>Непоследовательно...


Скажу больеш — ошибочно. Или мы оба варианта рассматриваем как вычисление, или как возврат значений. Иначе получается мешанина.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:48
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании.


VD>Это в корне не верное предположение. Объект может быть устроен как угодно. В том числе он может запоминать создаваемые экземлпяры в неком глобальном массиве. Стало быть, любые предположения могут быть невреными.


VD>Именно по этому объекты рассматривают как черные ящики имеющие только публичный интерфейс и некое оговариваемое поведение. Последнее и обуславливает то как можно использовать объект.


Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


VD>Если тебе нужно думать о таких вещах, то это уже признак того, что класс спроектирован из рук плохо.


VD>Зачем куда-то лезть? Если тебе возвращают SqlCommand, то это уже подразумевает, что команда должна быть должным образом инициализирована. Если тебе нужно каждый раз лезть в кишки методов, чтобы понять как их использовать, то или ты очень неуверен в себе и всего боишся, или ты имешь дело с кривой и неудобной библиотекой (кодом).


Ну вот уже перешли на личности Я прагматичный человек, не верю в абстрактные лозунги (ООП, правильное проектирование и т.п.) и очень неуверен в других А также понимаю, что проблему можно видеть очень по-разному и соответственно с объектами работать очень по-разному. Так что когда мне возвращают SqlCommand — я задаюсь вопросом — а какой connection он использует? Нет передано ли туда уже каких-либо параметров и прочее, и прочее.

VD>Из кода должна быть понятна логика, а не информация о типах. Или тогда уж нужно быть последовательным. Почему тебе нужна информация только о том конструктор это или нет? А информация о типах параметров тебе не нужна? Давай тогда как это делали на С/С++ вписывать в имена всех переменных префиксы описывающие типы. Ведь С-подобные языки (да и почти любые языки) не предоставляют описание типов аргументов вызова.


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

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


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


Кэр>>Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена.


VD>Не соглашусь. Чем меньше лишних деталей, тем проще как раз ухватить суть программы. А уж если тебе для понимания потребуется информация о неком идентефикаторе, то ты всегда можешь подвести к нему мышку и поглядеть хинт.


Ну да Есть пример такого языка — Perl. Очень кратко. Но зачастую понять это чириканье просто нереально.

VD>Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.


Весьма спорное утверждение.

Кэр>> Вот это ни разу не привычный мне внешний вид кода.

Кэр>>
Кэр>>def calc() : bool
Кэр>>{}
Кэр>>

Кэр>>Просто этот код гораздо более информативный, чем этот:
Кэр>>
Кэр>>def calc()
Кэр>>{}
Кэр>>

Кэр>>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

VD>Да не проблема, если тебе кажется это лучшим ты имешь право вставить тип явно. Более того ты можешь указать тип даже там где в C# это сделать невозможно. Свобода выбора!


Не спорю. Просто, имхо, это должно быть что-то вроде guideline разработки — использовать вывод типов именно там, где это принципиально сокращает и упрощает код. А не просто везде, где только можно.

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


Тогда их указывать не надо.

VD>Если все спроектировано грамотно, то все будет ОК. А нагородить ошибок можно и без того. К тому же я не понимаю какой смысл обсуждать факт? Это реальность и о ней нужно знать.


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

VD>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

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

То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

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

VD>
VD>def strCreator = string;
VD>def someFanction(f)
VD>{
VD>    f(array['H', 'i', '!'])
VD>}

VD>WriteLine(someFanction(strCreator));
VD>


Да, это интересный пример.

VD>И того у нас получается:

VD>1. Функция — это превокласное значение в Немерле. Ею можно гибко манипулировать.
VD>2. Конструктор — это тоже частный вид функции.
VD>Ну, и вывод:
VD>Мы получаем мощнейшие выразительные средства функциональной декомпозиции. И все это благодаря тому, что наш язык более абстрактен нежели закомплексованные императивные предшественники.
С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Функциональное программирование в Nemerle
От: anonym469  
Дата: 31.05.07 16:38
Оценка: -4
Здравствуйте, VladD2, Вы писали:

VD>Просто автор "забыл" привести две тонны кода эмулируюих паттерн матчинг.

Тот же автор, также забыл без всяких кавычек привести код, реализующий паттерн матчинг и варианты из компилятора Nemerle.

VD>не мало кода,

Существенного кода пока не более 30 строк. Посмотрим, что будет если мне приведут более сложные образцы.

VD>но он будет еще и тормозным

Это есть, но код пока достаточно прост, а оптимизация производительности делается в последнюю очередь.

VD>и не универсальным.

Достаточно универсален. Это видно по тому, что в Replace передается тип Expr.

VD>Дело в том, что паттерн-матчинг — это не очень тривиальная вещь.

Сильно зависит от грамматики паттерна.

VD>Достичь того же самого эмуляцией невозможно.

Тут отчасти соглашусь, однако напоминаю, что речь шла о пятикратном преимуществе по размеру кода.
А для доказательства эффективности Nemerle и не надо было городить никакой калькулятор, а просто сравнить String.Format("{0}", o) и "$o".

VD>Любое усложнение образцов будет усложнять задачу на порядки.

Пока примеров сложных образцов не увидел.
Re[6]: Функциональное программирование в Nemerle
От: anonym469  
Дата: 31.05.07 16:39
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>что развил всю тему.

Звучит как похвала.
Re[6]: Функциональное программирование в Nemerle
От: Иванков Дмитрий Россия  
Дата: 31.05.07 18:56
Оценка:
Здравствуйте, VladD2, Вы писали:

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


N>>В Nemerle вызов конструктора не всегда возвращает новый объект.


VD>Можно с этого места по подробнее? О чем речь?


Видимо о variant без полей
class A {}
variant B {|Q}
A () : object != A () : object;
B.Q () : object == B.Q () : object;

В частном случае с [] это практически очевидно и не бросается в глаза, а вот про произвольный variant как-то раньше не задумывался.
Re[8]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.07 00:39
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


Дык трудно уловимые ошибки и появляются когда совпадают несколько не очень часто появляющихся особенностей.

Кэр>Ну вот уже перешли на личности Я прагматичный человек, не верю в абстрактные лозунги (ООП, правильное проектирование и т.п.) и очень неуверен в других А также понимаю, что проблему можно видеть очень по-разному и соответственно с объектами работать очень по-разному. Так что когда мне возвращают SqlCommand — я задаюсь вопросом — а какой connection он использует? Нет передано ли туда уже каких-либо параметров и прочее, и прочее.


Это плохой подход. Все узнать нельзя. Нужные вещи должны оговариваться отдельно. А остальное должно жить на тестировании и разумных умолчаниях.

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

VD>>Из кода должна быть понятна логика, а не информация о типах. Или тогда уж нужно быть последовательным. Почему тебе нужна информация только о том конструктор это или нет? А информация о типах параметров тебе не нужна? Давай тогда как это делали на С/С++ вписывать в имена всех переменных префиксы описывающие типы. Ведь С-подобные языки (да и почти любые языки) не предоставляют описание типов аргументов вызова.


Кэр>Зачем сходить с ума?


Хороший вопрос. Задай его себе .

Кэр> Конкретно в этом случае совершенно сразу неочевидно, что scan, принимающая параметр типа Token — это и есть практически та функция, которая ответит на ключевой вопрос парности скобок. А если указать тип возвращаемого значения сразу при декларации сигнатуры функции scan — уже понятно, что скорее всего это именно эта функция и ее содержимое будет читаться уже вкупе с этим знанием.


И в чем проблема? Если тебя занимает вопрос о типе возвращаемого значения при чтени, то подведи мышку. Если все и так очевидто, то двигай дальше!

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


Тянуться как раз не долго. Да и нужно это редко. А с bool тебе уже сказли. Да в данном случае он вряд ли повредит читабельности. А в более сложном — может. Так что в правило это воодить нельзя. Разве что для примера в статьях. Там это актуально.

Кэр>Ну да Есть пример такого языка — Perl. Очень кратко. Но зачастую понять это чириканье просто нереально.


Перл — это, кстати, по сегодняшним временам не очень кратко. И плохая читабельность там из-за невнятных соглашений (разных переменных и т.п.). Да и с хинтами там вроде бы не здорово. В прочем какие на фиг хинты если их смотреть негде? Ведь неявные переменные на то и не явные, чтобы их тяжело было отследить .

VD>>Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.


Кэр>Весьма спорное утверждение.


Это не утверждение, а констатация факта. Это кстати, не мое утверждение. Но поклонники динамики в один голос это заявляют.

В прочем, я тоже согласен, что зачастую в том же Шарпе аннотация типов избыточна. Те же анонимные методы это отлично показывают. И их модификация в C# 3.0 говорит о том, что авторы это тоже признают.

Кэр>Не спорю. Просто, имхо, это должно быть что-то вроде guideline разработки — использовать вывод типов именно там, где это принципиально сокращает и упрощает код. А не просто везде, где только можно.


Тут guideline один. Считашь, что что-то невнятно? Считашь, что аннотация типов увеличит читабельность? Вставь ее. Вставил? Код не загромоздился? Зашибись. Загромоздился? Фигово. Стоит подумать над тем, чтобы убрать аннотацию.

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

Кэр>Я к тому, что не надо никогда не забывать о реальности и в первую очередь при проектировании языка и правил хорошего оформления кода на этом языке.


Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.

VD>>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

Твоих "если" просто не происходит на практике. Что обсуждать гипотетические проблемы?

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

Кэр>То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

Что тоже самое? Ты говорил, что плохо думать о конструктре как о фунции, а значит плохо когда они синтаксически неотличимы.

Кэр>Да, это интересный пример.


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

Кэр>С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно


Вот я уже считай год языком пользуюсь и не разу этого не наблюдал. Значит все же это предпрассудок.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Функциональное программирование в Nemerle
От: ie Россия http://ziez.blogspot.com/
Дата: 01.06.07 03:58
Оценка: 4 (1) +1
Здравствуйте, Кэр, Вы писали:

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


Ты ИМХО сам запутался в своих мыслях, а может я просто не могу понять их ход
Поэтому давай по порядку, с каким из этих утверждений ты не согласен и почему?
1. Думать о них как о близнецах-братьях не стоит пишущему конструктор.
2. Думать о них как о близнецах-братьях можно использующему конструктор.

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

Кэр>Как ты думаешь, что произойдет, если создать экземпляр Derived класса?
Кэр>
Кэр>public abstract class Base
Кэр>    {
Кэр>        public Base()
Кэр>        {
Кэр>            Log("Instance created");
Кэр>        }

Кэр>        public abstract void Log(string message);
Кэр>    }

Кэр>    public class Derived : Base
Кэр>    {
Кэр>        public Derived()
Кэр>        {
Кэр>             //_logMessages = new StringBuilder();
Кэр>        }

Кэр>        private StringBuilder _logMessages = new StringBuilder();

Кэр>        public override void Log(string message)
Кэр>        {
Кэр>            _logMessages.Append(message);
Кэр>            Console.WriteLine(message);
Кэр>        }
Кэр>    }
Кэр>


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

VD>>2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.

Ну нет же, споришь. Если я пишу конструктор, то да, я должен отновится к нему по другому, если я его использую, то какая мне разница — конструктор это, банальный метод или локальная функция. NRE ведь не только в конструкторах с виртуальными методами может вылитеть.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 13.06.07 05:52
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>Почему только тебя? Я сам по началу был немного обескуражен другим стилем записи.


VD>Код типа:

VD>
VD>def f(x)
VD>{
VD>  when (x)
VD>    1;
    
VD>    2;
VD>}
VD>

VD>я воспринимал как:
VD>
VD>int f(bool x)
VD>{
VD>  if (x)
VD>    return 1;
        
VD>  return 2;
VD>}
VD>

VD>и первое время входил в ступо когда компилятор выдвавл предупреждение о том, что игнарируется каое-то там значение.

Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров и уже дальше идет вычисление функции. Мне действительно интересно, как предлагается оформлять следующую логику в Nemerle:
Как данная логика должна быть оформлена в функциональном стиле? Вопрос скорее всего от малой практики использования того же pattern-matching'а. Но мне как новичку интересно

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


VD>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Вполне возможно

VD>Кстати, в C# 3.0 появятся лямбды — анонимные методы с выводом типов (гы-гы) и тела которых могут быть чистыми выражениями. Так вот в них будут такие же "проблемы". Тоже не будет return-ов и можно будет не указывать типы. Возможно, даже, что тип возвращаемого значения вообще нельзя будет задать явно. Так что привыкать по любому придется.


В расширенном синтаксисе лямбда выражений можно указывать тип входящего параметра и конечно же использовать return.

VD>>>Кстати, есть один вопрос:

VD>>>
VD>>>    | EndOfFile           => return stack.Count == 1
VD>>>        ...
VD>>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>>

VD>>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.


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


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

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


Это здорово, что концевые рекурсии распознаются и разворачиваются в цикл. Но ведь это подробности реализации по сути. Мы же говорим о "концептуальном понимании кода"
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 13.06.07 05:52
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


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


С этим не спорю. Но как тут отсутствие слова return может помочь — я не понимаю. Но привожу аргументы, чему отсутствие этого слова может помешать.

VD>Это плохой подход. Все узнать нельзя. Нужные вещи должны оговариваться отдельно. А остальное должно жить на тестировании и разумных умолчаниях.


VD>Так от команды тебе важно, чтобы она могла выполнить нужный тебе SQL. Пока это так (тесты работают) разбираться бессмысленно.


От команды мне нужно многое — чтобы она выполнила нужный мне sql, на нужном sql сервере, с нужными параметрами. Я согласен, что всего узнать нельзя. Просто когда я вижу просто вызов конструктора для обще-известного класса я не полезу в потроха конструктора, чтобы проверить как он инициализируется — если там что-то не так — очень быстро это станет известно.
Если же поставкой этого объекта занимается некий неизвестный мне интернальный framework и я первый раз его использую — я не только прочитаю документацию по вызову этого метода, но и скорее всего быстро пробегу по пути инициализации этого объекта.

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


VD>Тянуться как раз не долго. Да и нужно это редко. А с bool тебе уже сказли. Да в данном случае он вряд ли повредит читабельности. А в более сложном — может. Так что в правило это воодить нельзя. Разве что для примера в статьях. Там это актуально.


Согласен.

VD>Это не утверждение, а констатация факта. Это кстати, не мое утверждение. Но поклонники динамики в один голос это заявляют.


VD>В прочем, я тоже согласен, что зачастую в том же Шарпе аннотация типов избыточна. Те же анонимные методы это отлично показывают. И их модификация в C# 3.0 говорит о том, что авторы это тоже признают.


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

VD>Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.


Не надо из частного случая и частного опыта выводить общее правило. Я вот тоже думал, что рассуждения о beforefieldinit аттрибуте при определении ленивого синглтона через static конструктор — рассуждения сугубо теоритические. И вот недавно в проекте наступили на эту проблему весело и с размаху
Проблема с вызовом виртуальных методов в конструкторах — тоже себе вполне живая и забывать о ней не стоит.


VD>>>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>>И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

VD>Твоих "если" просто не происходит на практике. Что обсуждать гипотетические проблемы?


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

Кэр>>То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

VD>Что тоже самое? Ты говорил, что плохо думать о конструктре как о фунции, а значит плохо когда они синтаксически неотличимы.


Кэр>>Да, это интересный пример.


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


Кэр>>С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно


VD>Вот я уже считай год языком пользуюсь и не разу этого не наблюдал. Значит все же это предпрассудок.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: ie Россия http://ziez.blogspot.com/
Дата: 13.06.07 07:56
Оценка: 2 (1) +2
Здравствуйте, Кэр, Вы писали:


Кэр>Мне действительно интересно, как предлагается оформлять следующую логику в Nemerle:

Кэр> Кэр>Как данная логика должна быть оформлена в функциональном стиле? Вопрос скорее всего от малой практики использования того же pattern-matching'а. Но мне как новичку интересно

Pattern-matching тут как-то не к месту. Как-то так:
    public M(s : string, i : int, dt : DateTime) : IList[string]
        requires i > 0                           otherwise throw ArgumentException("i")
        requires dt.Year > 1950 && dt.Year <2010 otherwise throw ArgumentException("dt")
    {
        mutable e = try { E.Parse(typeof (E), s) :> E } catch { _ => E.Unknown }

        List()
    }

Немного подправил форматирование. Мне кажется так оно будет выглядеть лучше.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[10]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.06.07 14:27
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>От команды мне нужно многое — чтобы она выполнила нужный мне sql, на нужном sql сервере, с нужными параметрами.


Значит ты до сих пон не понял значение слова "абстракция" или не проникся всей важностью этого понятия.

Кэр> Я согласен, что всего узнать нельзя. Просто когда я вижу просто вызов конструктора для обще-известного класса я не полезу в потроха конструктора, чтобы проверить как он инициализируется — если там что-то не так — очень быстро это станет известно.

Кэр>Если же поставкой этого объекта занимается некий неизвестный мне интернальный framework и я первый раз его использую — я не только прочитаю документацию по вызову этого метода, но и скорее всего быстро пробегу по пути инициализации этого объекта.

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

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

В общем, практика показывает, что конструкторы без new не только не создают проблем для чтения, но и упрощают его. Кода становится меньше и он начинает выглядеть более естественно.

Кэр>Да, при объявлении анонимных функций часто можно опускать типы входящих параметров и результата. Пока это умолчание не становится повсеместным... Но не будем по второму кругу


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

VD>>Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.


Кэр>Не надо из частного случая и частного опыта выводить общее правило.


Никто этого и не делает. Просто все на свете частный случаи. Я тебе говорю о том, что просто не стоит искать гипотетические проблемы. Они или есть (реально, на практике) или их нет. Тут нужно просто тупо пробовать и смотреть на результат. Мой опыт показывает, что проблем в отсуствии аннотаций типов нет. И я довольно давно пишу на этом языке. Со временем появится статистика. Вот тогда и посмотрим. А мнение людей которые в основном писали только на языках с обязательной и повсеместной аннотацией типов изначально предвзятое. Нужно чтобы прошло хотя бы пол года после того как такие люди начинают использовать язык с выводом типов, чтобы их мнение можно было бы счесть более-менее не предвзятым.

Кэр> Я вот тоже думал, что рассуждения о beforefieldinit аттрибуте при определении ленивого синглтона через static конструктор — рассуждения сугубо теоритические. И вот недавно в проекте наступили на эту проблему весело и с размаху

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

Тут дело какое? Если на грабли наступают часто и стройными рядами, то это косяк в языке/рантайме и т.п. А если это разовый случай, то это лучше списать на то, что конкретные программисты немного ступили.

Всех проблем не избежать. Более того, то что кажется одному проблемой для другого является очень удобной вещь. Так что клеймить что-то граблями нужно только если на них наступают много народа.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.06.07 14:27
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров


Откровенно говоря не знаю что означает слово "санитизация". Если под этим термином понимается проверка параметров на граничные условия с генерацией исключений, то или как показал ie или с помощью макроса assert(), который генерирует специфичное условие.

В прочем и when тут подойдет, так как исключение по любому прерывает метод и думать о ветвлении не нужно. Но вариат ie конечно же оптимальный. Только чтбы он работал нужно октрыть (using) пространство имен Nemerle.Assertions.

VD>>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Кэр>Вполне возможно


100%! И это не только мои наблюдения. Например, IT, тоже в начале тыкался в return-ы, а потом признался, что когда пишет на Шарпе начал ловить себя на мысли, что недоволен тем, что приходится без особой нужды тыкать ретурны.

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

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


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

Кэр>Я имел ввиду следующее — на уровню абстракций при вызове другой функции мы увеличиваем стэк вызова.


Что это за абстракция такая если инам нужно думать о каких-то там деталях релизации компилятора?

Кэр> Грубо говоря — делаем типичный шаг в некотором цикле. Так вот — при программировании цикла большинтсво проблем обычно пожинаются при задании условий входа в цикл и выхода из цикла. Поэтому к ним нужно обращать максимальное внимание. Собственно за этим и я предлагал оставить return — как отметку, что здесь мы начинаем раскручивать стэк вызова обратно — в этом месте мы по сути начинаем выходить из "цикла", это нужно заметить, нужно посмотреть какие условия выхода и пр.


На самом деле лучше всего в таких случаях пользоваться рекурсией. Она же в Немерле бесплатная. Тогда у тебя как бы происходит переворот в сознании. Условия перестают "размещаться" в конце и начале цила. Вместо этого они становятся основной идеей алгоритма. А ветвление управления производится с помощью рекурсивного вызова. Вот, напирмер, код парсинга $-строки где выделяются "..$xxx", "..$(...)", "$xxx", "$(...)", ведущие пробельные символы, концы строк и просто текст. Вместо того, чтобы создавать сложный и непонятный ДКА на циклах и свитчах, я просто воспользовался рекурсивными вызовами

def loop (res : list[StrPart]) : list[StrPart]
{
  nestLevel++; Diagnostics.Trace.Assert(nestLevel < 200); // Prevent stack owerflow
  
  // Завершает акомуляцию сиволов литерала и создает соотвествующую 
  // лексему добавляя ее к началу списка лексем
  def endLiteral()
  {
    if (strBuilder.Length == 0)
      res
    else
    {
      def str = strBuilder.ToString();
      strBuilder.Length = 0;
      StrPart.Lit(str) :: res
    }
  }
  def isNextDollar(n)
  {
    def ch1 = peekN(n);
    if (char.IsWhiteSpace(ch1)) isNextDollar(n + 1)
    else                        ch1 == '$'
  }
  def isElipse() { peek() == '.' && isNextDollar(2) }
  def processNewLine() { loop (StrPart.NewLine() :: endLiteral()) }
  
  match (next())
  {
    | '\0'                     => endLiteral()
    | '$'                      => parceSpliceEx(endLiteral(), index, true)
    | '.'  when isElipse()     => index = str.IndexOf('$', index);
                                  parceSpliceEx(endLiteral(), index, false); // '..$'
    | '\r' when peek() == '\n' => _ = next(); processNewLine()
    | '\n' | '\r'              =>             processNewLine()
    | x                        => _ = strBuilder.Append(x); loop(res)
  }
}

Алгоримт при этом становится совершенно очевидным и практически не требует документирования.

Кэр>Это здорово, что концевые рекурсии распознаются и разворачиваются в цикл. Но ведь это подробности реализации по сути. Мы же говорим о "концептуальном понимании кода"


Ошибаешся. Это как раз подробности спецификции языка. Для ФЯ гарантия оптимизации концевой рекурсии является очень важной. Без этого писать в фунциональном стиле становится опасным для производительности.

Кстати, забавный факт. В самом языке (Немерле) вообще нет циклов! Они все эмулируются макросами. А макросы как раз переписывают циклы в рекурсивные фуцнии. Так что фактически использование рекурсивных фуцний быстрее нежели for, foreach, while и т.п., так как они в лучшем случае будут переписаны в такую же фунцию. Ну, а при генерации MSIL-а компилятор обратно превратит функции с концеовой рекурсией в циклы. И все это прозрачно для программиста. Он может думать, что язык одинаково хорошо поддерживает как фунции с концевой рекурсией, так и все виды циклов. Даже цикл вида:
foreach (i in [1..10])
 ...

будет генерировать быстрый код.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Warturtle  
Дата: 26.06.07 17:38
Оценка:
Здравствуйте, VladD2, Вы писали:

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


Кэр>>Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров


VD>Откровенно говоря не знаю что означает слово "санитизация". Если под этим термином понимается проверка параметров на граничные условия с генерацией исключений, то или как показал ie или с помощью макроса assert(), который генерирует специфичное условие.


VD>В прочем и when тут подойдет, так как исключение по любому прерывает метод и думать о ветвлении не нужно. Но вариат ie конечно же оптимальный. Только чтбы он работал нужно октрыть (using) пространство имен Nemerle.Assertions.


VD>>>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Кэр>>Вполне возможно


VD>100%! И это не только мои наблюдения. Например, IT, тоже в начале тыкался в return-ы, а потом признался, что когда пишет на Шарпе начал ловить себя на мысли, что недоволен тем, что приходится без особой нужды тыкать ретурны.


VD>Просто в мозгу в какой-то момент происходит счелчек и ты переключаешся на мышление в терминах выражений. После этого нетурны тебе становятся нужны исключительно тогда, когда алгоритм проще записать императивно. Например, когда нужно выйти из foreach. Да и происходит не часто.


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


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


VD>...


Да — нету в C# "искры Божьего гнева", а в Немерле, бзпсд, есть...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.