Есть у меня на скале маленькая библиотечка валидаторов параметров запроса, позволяющая составлять сложные цепочки валидаторов следующим образом:
val v = VRequired & VInt & VRange(0, 100)
val r: Result[Int] = v("99", default = 0)
... if (r.ok)
... r.data
Вопрос такой: если мне приспичит получить похожий (операторный) синтаксис на N, как реализовывать? Меня смущает, смогу ли я заюзать стандартный оператор & либо уже имеющийся в макросах && в нестандартной семантике? На скале оператор — это просто метод своего левого аргумента, наличие одинаковых имён операторов у разных классов и overloaded operators — нормальная практика. Влад в статьях давал пример макроса "&&", и это в некотором смысле аналогично глобальной функции. На видео с конференции он показывал код макроса "?." и этот код содержит знание о типах, с которыми он работает. Насколько я вижу, здесь имеет место быть нерасширяемая семантика, гвоздями прибитая к синтаксису. Правильно ли я понимаю, что чтобы избежать конфликта имён (в т.ч. если в одном модуле будут использоваться и мои валидаторы, и другие макробиблиотеки), мне нужно придумать некий условно-уникальный оператор @%#$@&^!, т.к. в уже объявленные не влезешь? Упоминаний о "macro overloading" (прости господи) пока что не видел (третью часть видео ещё не смотрел). Или, наверное, более правильный вопрос: какой подход порекомендуют немерлисты для реализации аналогичного функционала? VRequired.And(VInt.And(VRange(0, 100))) не предлагать.
Здравствуйте, kochetkov.vladimir, Вы писали:
D>>Теперь видел. Любопытно, но к моему вопросу отношения не имеет.
KV>Ну... ты же говорил про валидацию параметров HTTP-запросов, не?
Хм. Если уж на то пошло, то во-первых, некорректное значение параметра запроса — это штатная ситуация, и юзать для её ловли исключения — не есть гуд. А во-вторых, эти же валидаторы у меня используются в формах, и там надо коллекционировать ошибки валидации всех полей, получается try/catch внутри цикла, криво (хотя это следствие из п.1). В общем, в данном случае чисто функциональная логика лучше.
А вопрос про operator overloading у любого скала-программиста в том или ином контексте так или иначе вылезет.
Здравствуйте, dimgel, Вы писали:
D>Хм. Если уж на то пошло, то во-первых, некорректное значение параметра запроса — это штатная ситуация, и юзать для её ловли исключения — не есть гуд.
Это весьма холиварный вопрос, кстати. Если тебе в поле email пришло "bla-bla-bla", то я еще могу согласиться с тем, что это штатная ситуация. Если же это самое "bla-bla-bla" тебе пришло в поле pageNumber, то это должно быть исключением, т.к. нарушает контракт точки входа в веб-приложение и является событием безопасности, которое должно быть сохранено в журнал событий с тем, чтобы в дальнейшем ты мог реконструировать происходившее на твоем веб-сервере.
Здравствуйте, kochetkov.vladimir, Вы писали:
D>>Хм. Если уж на то пошло, то во-первых, некорректное значение параметра запроса — это штатная ситуация, и юзать для её ловли исключения — не есть гуд.
KV>Это весьма холиварный вопрос, кстати. Если тебе в поле email пришло "bla-bla-bla", то я еще могу согласиться с тем, что это штатная ситуация. Если же это самое "bla-bla-bla" тебе пришло в поле pageNumber, то это должно быть исключением, т.к. нарушает контракт точки входа в веб-приложение и является событием безопасности, которое должно быть сохранено в журнал событий с тем, чтобы в дальнейшем ты мог реконструировать происходившее на твоем веб-сервере.
Мог бы и поспорить. Если у меня есть js-проверки полей на клиенте, мне и email не должен неправильный прийти. Это уже логика приложения — определять степень серьёзности той или иной ошибки. Ни разу не видел фреймворков, поддерживающих подобное богатство возможностей parameter binding & validation "из коробки". Не то чтобы я их вообще много видел, но представить себе, к примеру, что в стандарте JSR303 в дополнение к @NotNull вдруг появится @SeriousNotNull, не могу.
Но давай может вернёмся к исходному вопросу? Попробую если не переформулировать, то поставить акцент: компактный хорошо читабельный (операторный?) синтаксис + отсутствие потенциальных конфликтов с другими макробиблиотеками.
Здравствуйте, dimgel, Вы писали:
D>Но давай может вернёмся к исходному вопросу? Попробую если не переформулировать, то поставить акцент: компактный хорошо читабельный (операторный?) синтаксис + отсутствие потенциальных конфликтов с другими макробиблиотеками. операторы можно перегружать как макросами, так и статическими методами как в шарпе (сам не пробовал)
а макросами можно сделать вообще всё что душе угодно
KV>>Это весьма холиварный вопрос, кстати. Если тебе в поле email пришло "bla-bla-bla", то я еще могу согласиться с тем, что это штатная ситуация. Если же это самое "bla-bla-bla" тебе пришло в поле pageNumber, то это должно быть исключением, т.к. нарушает контракт точки входа в веб-приложение и является событием безопасности
D>Мог бы и поспорить. Если у меня есть js-проверки полей на клиенте, мне и email не должен неправильный прийти.
рассмотри ситуацию, как твой сервер ломают
Здравствуйте, para, Вы писали:
KV>>>Это весьма холиварный вопрос, кстати. Если тебе в поле email пришло "bla-bla-bla", то я еще могу согласиться с тем, что это штатная ситуация. Если же это самое "bla-bla-bla" тебе пришло в поле pageNumber, то это должно быть исключением, т.к. нарушает контракт точки входа в веб-приложение и является событием безопасности
D>>Мог бы и поспорить. Если у меня есть js-проверки полей на клиенте, мне и email не должен неправильный прийти. P>рассмотри ситуацию, как твой сервер ломают
Именно это я и имел в виду: это будет нештатная ситуация, являющаяся событием безопасности. Я этим примером как раз и продемонстрировал, что никакой резницы между "bla-bla-bla" в полях email и pageNumber может и не быть. И как правило, её и нет.
Здравствуйте, dimgel, Вы писали:
D>Всем привет.
D>Есть у меня на скале маленькая библиотечка валидаторов параметров запроса, позволяющая составлять сложные цепочки валидаторов следующим образом:
D>
D>Вопрос такой: если мне приспичит получить похожий (операторный) синтаксис на N, как реализовывать?
Если VRequired это свой тип, то правильный способ — как catbert порекомендовал.
Если же VRequired расширять нельзя, то можно поступить аналогично идеи с computation expressions — переписывать код внутри явно указанного скопа; такой подход хорош, когда разрабатывается фреймворк, в рамках которого могут быть и другие макросы, которые можно ограничить этим же скопом; сам скоп можно назвать по имении фреймворка, например:
def v = libweb VRequired & VInt & VRange(0, 100);
def r : option[int] = v("99", default = 0);
... if (r.HasValue) {
... r.Value
Где libweb — макрос, который переписывает код, переданный в аргументе. Из положительных сторон такого похода — неизвестный макрос libweb сразу намекает на то, что происходит магия.
Здравствуйте, dimgel, Вы писали:
D>Ни разу не видел фреймворков, поддерживающих подобное богатство возможностей parameter binding & validation "из коробки".
Мы сейчас как раз за такой хотим взяться. Присоеденяйся, если хочешь стать одним из авторов одного из самых интересных фрэймворков для веба. Других мы не делаем
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, dimgel, Вы писали:
D>Хм. Если уж на то пошло, то во-первых, некорректное значение параметра запроса — это штатная ситуация, и юзать для её ловли исключения — не есть гуд. А во-вторых, эти же валидаторы у меня используются в формах, и там надо коллекционировать ошибки валидации всех полей, получается try/catch внутри цикла, криво (хотя это следствие из п.1). В общем, в данном случае чисто функциональная логика лучше.
Создай свою реализацию (или несколько) которая будет делать то что надо тебе. Макросы ведь лежат в пространствах имен. В нужном месте сможешь открыть нужное пространство имен и заюзать нужную реализацию.
D>А вопрос про operator overloading у любого скала-программиста в том или ином контексте так или иначе вылезет.
Перегрузка операторов делается точно похоже на то как это делается в C#. В типе для которого делается перегрузка заводишь метод следующего вида:
using System.Console;
[Record]
class X
{
public Data : int;
public static @&(arg1 : X, arg2 : X) : bool
{
arg1.Valadate() && arg2.Valadate()
}
public Valadate() : bool { Data % 2 == 0 }
}
module Program
{
Main() : void
{
def x1 = X(1);
def x2 = X(2);
def x3 = X(4);
WriteLine($"x1 & x2: $(x1 & x2) x2 & x3: $(x2 & x3)");
_ = ReadLine();
}
}
и этот оператор вызовется вместо стандартного для типа X.
Можно и для разных типов перегрузку сделать.
Данный пример выводит:
x1 & x2: False x2 & x3: True
Единственное ограничение — оператор не должен быть виден в виде макроса в этой же области видимости. Так оператор && перегрузить не удается, так как он реализован макросом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Мы сейчас как раз за такой хотим взяться. Присоеденяйся, если хочешь стать одним из авторов одного из самых интересных фрэймворков для веба. Других мы не делаем
Я уже отнекивался, что ближайшие полгода не смогу.
Здравствуйте, dimgel, Вы писали:
VD>>Мы сейчас как раз за такой хотим взяться. Присоеденяйся, если хочешь стать одним из авторов одного из самых интересных фрэймворков для веба. Других мы не делаем
D>Я уже отнекивался, что ближайшие полгода не смогу.
Тогда тебе остается только ждать и облизываться .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.