Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 13:16
Оценка:
ну вот почти вторую неделю ковыряю Nemerle, по пути уже поглядел мельком на Roslyn поковырял Mono, и вот сижу и думаю, чего бы вбросить такого, что бы разгорелась жаркая дискуссия относительно Nemerle, а то я как посмотрю у вас тут одни сплошные потоки радости ). Но если чуть чуть серьезней, то понятно, что у Nemerle есть один большой "фатальный недостаток", но речь не о нем, хотелось бы узнать у сообщества, есть ли что-то что вам не совсем нравится в Nemerle, или совсем не нравится.
У самого есть несколько вопросов, но быть может все об этом и так знают и поэтому не стоит о них ни кому говорить.
Re: Недотатки Nemerle
От: Don Reba Канада  
Дата: 18.06.12 13:56
Оценка:
Здравствуйте, cNoNim, Вы писали:

NN>Но если чуть чуть серьезней, то понятно, что у Nemerle есть один большой "фатальный недостаток", но речь не о нем, хотелось бы узнать у сообщества, есть ли что-то что вам не совсем нравится в Nemerle, или совсем не нравится.


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

Всё ещё довольно часто спотыкаюсь об ошибки в компиляторе. О наиболее неприятных пишу в трэкер на гитхабе, но исправлять их никто, особо, не собирается. Самому тоже не хочется т.к. — см. предыдущий параграф.
Ce n'est que pour vous dire ce que je vous dis.
Re: Недотатки Nemerle
От: Аноним  
Дата: 18.06.12 14:11
Оценка:
Здравствуйте, cNoNim, Вы писали:

Основной недостаток это отсутствие родных библиотек. На библиотеки .нет ручками махать не надо, они совсем сделаны без макросов и значит нет основного преимущества немерли.
Re: Недостатки Nemerle
От: Don Reba Канада  
Дата: 18.06.12 15:20
Оценка:
Вообще, уже была тема: Что вас раздражает или не нравится в Nemerle?
Автор: Ka3a4oK
Дата: 21.09.10
Ce n'est que pour vous dire ce que je vous dis.
Re[2]: Недотатки Nemerle
От: _Claus_  
Дата: 18.06.12 16:06
Оценка:
А>Основной недостаток это отсутствие родных библиотек. На библиотеки .нет ручками махать не надо, они совсем сделаны без макросов и значит нет основного преимущества немерли.

+1. Linq должен быть реализован как макробиблиотека, чтобы все разворачивалось и работало без всяких тормозов и замыканий. да и в остальном, в библиотеках N, нужен подход, основанный на описании в стиле UML. код писаться сам должен. иначе правы шарписты — выгоды в итоге сомнительны. если только не пишешь что-то очень хитрое. правда CodingUnit что-то похожее делал, никак руки не дойдут пощупать, насколько его разработка юзабельна, как основа системы.
Re[2]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 16:19
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>Вообще, уже была тема:

спасибо как раз то что я плохо искал )))
щас сформулирую свои вопросы на основе прочитанного в той теме
Re[3]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 19:06
Оценка:
большая часть той темы посвящена очень важной проблеме просто "фатальному недостатку"
не возможно написать
a=-1;

без условно очень важная проблема, но тут я согласен с позицией влада, так что поговорим о другом
в очередной раз в той теме я наблюдаю диалог вида
>>сообщество:
>>хотелось бы не писать типы вообще
>VladD2:
>даже в хаскеле указание типов считается правилом хорошего тона считается
либо
>если разрешить глобальный вывод типов, то при внесении изменений возможно потребуется выводить типы для всего проекта заново
и знаете, что меня в этом смущает...
Влад почему то не договаривает, либо он слабо знаком допустим с тем же хаскелем, либо знаком, но не договаривает
давайте рассмотрим простой пример
using System;
public class Program
{
    public static Main() : void
    {    
        def foo(a, b) {
            a + b
        };
        Console.WriteLine($"$(foo(1, 2))$(foo(1.0, 2.0))$(foo(1, 2.0))");
    }
}

да да, вы правильно поняли оно не будет работать
потому, что даже локальные функции конкретизируются в момент первого применения, и конкретизируются они конкретным типом, ну точнее как конкретным
компилятор увидев вызов второй функции с аргументами другого типа попытается пройтись по иерархии типов, и найти общего предка который мог бы удовлетворить условия, но к сожалению он его не найдет, но даже допустим такой предок есть, как в следующем коде
using System;
public interface IFoo
{
    foo (x : IFoo) : IFoo*IFoo;
}

public class Foo : IFoo
{
    public foo (x : IFoo) : IFoo*IFoo 
    {
        (this, x)
    }

    public foo(x : Foo) : Foo*Foo
    {
        (this, x)
    }    
}

public class Bar : IFoo
{
    public foo(x : IFoo) : IFoo*IFoo
    {
        (x, this)
    }

    public foo(x : Bar) : Bar*Bar
    {
        (x, this)
    }
}

public class FooBarExtentions
{
    public static foo(this b : Bar, f : Foo) : Foo*Bar
    {
        (f, b)
    }
    public static foo(this f : Foo, b : Bar) : Foo*Bar
    {
        (f, b)
    }
}

public class Program
{
    
    public static Main() : void
    {    
        def foo(a, b) {
            a.foo(b)
        };
        Console.WriteLine($"$(foo(Bar(), Bar()))$(foo(Foo(), Foo()))$(foo(Bar(), Foo()))");
    }
}

казалась бы проблема решена, но почему то от ее решения мне становится грустно
nemerle сгенерировал для функции foo следующий код\
private static Tuple<IFoo, IFoo> _N_foo_4280(IFoo a, IFoo b)
{
    return a.foo(b);
}

т.е. как и было ожидаемо конкретизировал функцию до интерфейса IFoo, хотя все можно было сделать гораздо красивее
в общем дабы не расписывать кучу проблем подобной конкретизации, я лучше приведу пример
и тут я бы сказал, что даже в С++ дела обстоят куда лучше
#include <utility>
#include <iostream>

template<typename T1, typename T2>
auto foo(T1 x, T2 y) -> decltype(std::forward<T1>(x) + std::forward<T2>(y))
{
    return std::forward<T1>(x) + std::forward<T2>(y);
}

int main()
{
    std::cout << foo(1, 2) << foo(1.1, 2.2) << foo(1, 2.2);
    std::cin.get();
}

знающие люди увидят, что здесь на самом деле будет не одна шаблонная функция, а три
компилятор С++ проинстанцирует 3 специализации функции foo для каждого сочетания шаблонных параметров,
так же кто то скажет, что это не совсем вывод типов и что это вообще шаблоноговнокод,
но он очень хорошо показывает то о чем я хочу сказать
и чего бы я хотел видеть в Nemerle, а если точнее, то конкретизацию не при первом использовании, а при каждом
...
продолжение следует
Re[4]: Недостатки Nemerle
От: catbert  
Дата: 18.06.12 19:16
Оценка: 1 (1) +2
Здравствуйте, cNoNim, Вы писали:

NN>и чего бы я хотел видеть в Nemerle, а если точнее, то конкретизацию не при первом использовании, а при каждом


Ну, это так и задумывалось: выводится всегда самый конкретный тип. Это потому что при создании Немерле была цель как можно лучше работать с .NET, а в .NET шаблоны не приняты, в нем рулят генерики. А генерики лучше объявлять явно. В Немерле можно объявить, что функция генерик (как в С++), и тогда все будет работать четко.

К сожалению, эту фичу хотят удалить, и я не понимаю, почему.
http://nemerle.rsdn.org/banners/?t=%20catbert%20
Re[5]: Недостатки Nemerle
От: STDray http://stdray.livejournal.com
Дата: 18.06.12 19:48
Оценка:
C> В Немерле можно объявить, что функция генерик (как в С++), и тогда все будет работать четко.
C>К сожалению, эту фичу хотят удалить, и я не понимаю, почему.

Не понял, убрать функции параметризованные типом или что?
Re[6]: Недостатки Nemerle
От: catbert  
Дата: 18.06.12 20:00
Оценка:
Здравствуйте, STDray, Вы писали:

STD>Не понял, убрать функции параметризованные типом или что?


Локальные функции, параметризированные типом.
http://nemerle.rsdn.org/banners/?t=%20catbert%20
Re[4]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 20:04
Оценка:
NN>...
NN>продолжение следует
решение описываемой мной проблемы для локальных функций, как мне кажется всем очевидно и понятно, вместо одной функции
private static Tuple<IFoo, IFoo> _N_foo_4399(IFoo a, IFoo b)
{
    return a.foo(b);
}

компилятору, следовало бы генерировать 3 функции, для каждого применения функции foo
примерно так как это делает компилятор С++, но начал я говорить о глобальном выводе типов, а не о локальных функциях, а тут проблемы гораздо глубже, для того что бы их понять
можно обратить внимание на следующий код
using System;
public class Program
{
    public static Main() : void
    {    
        def foo(a, b) {
            a + b
        };
        Console.WriteLine("Hi, Bob!!!");
    }
}

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

исходя из всего сказанного можно было бы предложить несколько вариантов решения проблемы.
1) который ни чего не решает, но тем не менее его тоже необходимо рассмотреть.
если локальная функция не используется, ее вообще не должно быть в сборке, я думаю это вполне реализуемо, уже другой вопрос, что это нафиг ни кому не нужно, так как писать функцию, которая ни где не используется, глупость со стороны разработчика.
но ведь смотрите, к чему приводит отсутствие этой фичи.
допустим мы временно хотим закомментировать место использования функции, для того что бы попробовать другую реализацию допустим.
nemerle же вынуждает нас комментировать и саму функцию, хотя спокойно мог бы локальную то функцию и выбросить, пускай и выдав варнинг.
2) более сложный способ как мне кажется, и я не до конца понимаю как его реализовать, но тем не менее, он присутствует в хаскеле,
и называется классы типов, я реализовывал нечто вроде классов типов в С++ на шаблонах, на счет .net языков не уверен, что это реализуемо,
и в любом случае скорее всего приведет к тому что придётся пересматривать систему типов полностью.
так же потребуется вносить изменения в вывод типов, который должен будет выводить наиболее общий тип,
и подставлять его в реализацию функции в сборке,
а при каждом использовании, нужно будет инстанцировать конкретный тип,
3) способ я бы назвал компромиссным, т.е. мы не трогаем систему типов и стараемся остаться в рамках .net'а
заключается он в том, что в сборку подставляется не конкретный тип, а сгенерированный на лету интерфейс заглушка,
т.е. мы не пытаемся в месте объявления функции вывести тип, мы генерируем интерфейс заглушку и помечаем его каким либо атрибутом, который скажет нам что этот интерфейс необходимо конкретизировать в месте использования, таким образом в наружу у нас торчат публичные интерфейсы заглушки, которые точно так же можно использовать из .Net написав в ручную реализацию этих интерфейсов, а в компиляторе nemerle мы при встрече интерфейса с указанным атрибутом, мы пытаемся его конкретизировать в месте использования, и сгенерировав скрытую его реализацию.

тем самым возвращаясь к началу моего прошлого поста.
>если разрешить глобальный вывод типов, то при внесении изменений возможно потребуется выводить типы для всего проекта заново
это лукавство
в хаскеле присутствует cross module type inference, и компилятор не конкретизирует тип, а пытается вывести наиболее общий тип
таким образом нет необходимости перетипизироать модуль или связанные модули, но да в месте использования компилятор хаскеля,
уточняет тип функции, но не той функции, которая торчит наружу из модуля, а создает ее специализацию
таким образом вот этот чудесный код, который надеюсь будет понятен
module Main where
foo a b = a + b
main = putStrLn (show (foo 1 2) ++ show(foo 1.0 2.0) ++ show(foo 1 2.0))

без проблем компилируется
и выводит для функции foo следующий тип
foo :: forall a. GHC.Num.Num a -> a -> a -> a

и теперь второе лукавство
>даже в хаскеле указание типов считается правилом хорошего тона
для функции foo ведь можно указать тип
foo :: Int -> Int -> Int

и получить не компилируемый код, приведенный мной выше
а правилом хорошего тона, для подобных функций считается указание наиболее общего подходящего типа,
т.е. в ручную я бы указал его как то так
foo :: (Num a) => a -> a -> a

к сожалению nemerle не хаскель )))

PS: но я бы подумал, над предложенными мной способами обойти эту проблему
Re[5]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 20:08
Оценка:
Здравствуйте, catbert, Вы писали:

C>В Немерле можно объявить, что функция генерик (как в С++), и тогда все будет работать четко.

ну не совсем )
using System;
public class Program
{
    public static Main() : void
    {    
        def foo[T](a : T, b : T) : T {
            a + b
        };
        Console.WriteLine($"$(foo(1, 2))$(foo(1.0, 2.0))$(foo(1, 2.0))");
    }
}

ты не заставишь работать даже с генериками, это проблема генериков

+ я в том посте таки и предлага выводить самый конкретный тип, но не при первом использовании, а при каждом
в место 1 локальной функции генерировать несколько
Re[4]: Недостатки Nemerle
От: Don Reba Канада  
Дата: 18.06.12 20:21
Оценка:
Если нужны шаблоны, их не так сложно реализовать макросами — это уже неоднократно говорилось. Лично у меня на практике не встречалось такой потребности.
Ce n'est que pour vous dire ce que je vous dis.
Re[6]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 20:24
Оценка:
да и с генериками врятли можно реализовать что то лучше чем
using System;
public interface IFoo
{
    foo (x : IFoo) : IFoo*IFoo;
}

public class Foo : IFoo
{
    public foo (x : IFoo) : IFoo*IFoo 
    {
        (this, x)
    }

    public foo(x : Foo) : Foo*Foo
    {
        (this, x)
    }    
}

public class Bar : IFoo
{
    public foo(x : IFoo) : IFoo*IFoo
    {
        (x, this)
    }

    public foo(x : Bar) : Bar*Bar
    {
        (x, this)
    }
}

public class FooBarExtentions
{
    public static foo(this b : Bar, x : IFoo) : IFoo*Bar
    {
        (x, b)
    }
    public static foo(this f : Foo, x : IFoo) : Foo*IFoo
    {
        (f, x)
    }
}

public class Program
{
    
    public static Main() : void
    {    
        def foo[T](a : T, b : T) where T : IFoo {
            a.foo(b)
        };
        Console.WriteLine($"$(foo(Bar(), Bar()))$(foo(Foo(), Foo()))$(foo(Bar(), Foo()))");
    }
}

и в итоге получить
private static Tuple<IFoo, IFoo> _N_foo_4399<T>(T a, T b) where T: IFoo
{
    return a.foo((IFoo) b);
}

что опять же не совсем то, что хотелось бы увидеть
все равно вызовутся не самые конкретные фукнции классов Foo Bar
и возвращаемый тип опять же будет не конкретным
в общем генерики особо ни чем не помогают
Re[5]: Недостатки Nemerle
От: _Claus_  
Дата: 18.06.12 20:27
Оценка:
NN>PS: но я бы подумал, над предложенными мной способами обойти эту проблему

Боюсь, тебе будет трудно поверить, что причина описанных проблем кроется не в N, а в идеологии .Net. В ней замыкания принято иметь как одну функцию, и изменение этого вызовет массовую истерию. еще в .Net нет общего числового типа для int и double. и т.д. и т.п.
Re[6]: Недостатки Nemerle
От: Tissot Россия  
Дата: 18.06.12 20:34
Оценка:
Здравствуйте, cNoNim, Вы писали:

NN>ты не заставишь работать даже с генериками, это проблема генериков


В F#-е заставишь. Никто не заставляет генерить одну generic-реализацию для всех случаев.
Re[6]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 20:39
Оценка:
Здравствуйте, _Claus_, Вы писали:
_C_>Боюсь, тебе будет трудно поверить, что причина описанных проблем кроется не в N, а в идеологии .Net.
вот а я уж думал, неужели придётся самому это писать )))
без условно самый главный недостаток nemerle это .Net
все было бы проще если бы многие фичи вывода типов присутствовали не на уровне языков, а на уровне CIL
конкретизация типов должна присутствовать где то на уровне JIT, а на уровне компиляторов языков должен присутствовать вывод типов который выводит наиболее общий тип
Re[7]: Недостатки Nemerle
От: cNoNim Россия http://cnonim.name
Дата: 18.06.12 20:40
Оценка:
Здравствуйте, Tissot, Вы писали:
> Никто не заставляет генерить одну ...реализацию для всех случаев.
об этом и речь
Re[4]: Недостатки Nemerle
От: fddima Интернет  
Дата: 18.06.12 21:31
Оценка: 6 (2) +1
Здравствуйте, cNoNim, Вы писали:

Ты знаешь... это всё может быть важные, а может быть не важные проблемы.
Есть такой чуви, Алексей Пахунов — Not a kernel guy. Недавно дал интервью. Так вот мне очень понравился вопрос и ответ.

Каких возможностей вам не хватает в современных языках программирования?

Если в двух словах, то не хватает удобных средств борьбы со сложностью кода и возможности аналитически доказать корректность кода. К первым я бы отнес инструменты, помогающие находить сходные куски кода; диагностику, показывающую, как именно выполнялся код, как он может выполниться в похожих/граничных условиях; инструменты для статического и динамического анализа кода; возможность контролировать разрешённые конструкции языка; возможность расширять язык напрямую, вместо костылей типа перегрузки операторов и шаблонов в C++ и т.д.

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


Жирным выделил. Почему мне это понравилось — потому, что, человек, насколько я понимаю весьма далёк от C#, .NET и Nemerle, далёк не сколько по способностям — а сколько по опыту работы — но почему же то потребности те же?
И насколько я вижу — N — практически единственный язык позволяющий это. То что позволяет N — иногда можно достичь и другими средствами, вот недавние скринкасты с NDC доказывают это — но так элегантно — едвали кто способен. И я вот в N реально удручен синтакслм дженерик параметров, — всё таки угловые скобки — почти стандарт, а с другой стороны, а что в C++? — ставить пробел перед закрывающей скобкой — обязаловка ныне — смешно же! Проблемы парсера?!?!? Ну да — а народ то хавает.
Да, текущий N — не идеален. Ну так он только начал развиваться по настоящему, с подключением команды RSDN и людей около ней. В общем — чем больше я знакомлюсь с N — тем больше я в восторге и тем более готов прощать недостатки, ведь преимуществ гораздо больше — а недостатки по большей мере, отностятся лишь к привычкам. Если уже IT пропагандирует N — видимо стоит серьёзно задуматься. Серьёзно.
А от "C# на стероидах" я вообще в восторге — это ведь решение кучи проблем, с минимальным ломанием команды разрабов. Сейчас мне приходится городить в рантайме (извините, но в T4 это не менее легче, — IL сгенерить не сложнее) реализацию WCF клиента, который бы соответствовал моим требованиям, стандратный, и тот шо на кодеплексе — всё не то, по факту — я то же мог бы сделать на N и макросах просто таки в разы проще... да, я сейчас не тороплюсь всё подряд переписывать на N.
Год назад я просто смотрел на N — а сейчас — смотрю с очень большим интересом, и уже жду смотрю где его будет удачнее приткнуть в уже действующий проект. И самое главное — я уже давно вижу, что код на N с его def — это то чего мне нехватает в C#, меня реально парит, что нельзя объявить "алиас", — в методе из трёх строк — это не проблема, в методе из 50 — не проблема пока его не трогают, в коде который генерит C# — это проблема отродясь — слоты задействует без необходимости.
Да и "любые конструкции — выражение", мне лично давно не хватает.

В CefGlue юзаю C# — потому, что а) unsafe код. Перед Xilium.CefGlue/3 — думал о N — но всётаки плотно юзаю unsafe (хотя он почти весь генерённый), — тем не менее, даст бог и N подключу — вроде бы точки где его можно было бы применить — просматриваемы. Да, кстати, вопрос о том, что open-source и народ тянется к C# — ерунда. Народ тянется к бинарникам и нифига не хочет фиксить — так что язык реально пофигу. Те кто хочет что-либо пофиксить — не поленяться установить петон, N и не поленяться вообще сами сбилдить CEF, что гораздо затратнее по времени и ресурсам...

Вот вам и недостатки.

PS: На NDC IT — реально клёва рассказал — имхо, в какой-то степени даже лучше Филиппа. Хотя оба молодцы. Филиппу бы посоветовал снести только то говно, которое НЕ билдит проекты, а должно.
CefGlue: .NET CLR binding for The Chromium Embedded Framework (CEF)
Re[7]: Недостатки Nemerle
От: fddima Интернет  
Дата: 18.06.12 21:39
Оценка:
Здравствуйте, cNoNim, Вы писали:

Извиняюсь сразу за сарказм — JIT, безусловно делает много, а наверное должен ещё больше. Поэтому имея специальный префикс .tail call — он очень жестоко сливает на протяжении скольких уже лет — и его никто не использует.
CefGlue: .NET CLR binding for The Chromium Embedded Framework (CEF)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.