Pull to refresh

Comments 36

И вы до сих пор думаете, что С# и Java не были ошибками? Настолько сложные навороты вокруг абсолютно элементарной вещи, которая должна писаться в одну строку. А тут ещё и оверхед на рантайме огромный

Навороты конечно непростые, но про оверхед вы не правы. Эти "аппендеры" являются структурами нулевого размера, которые используются как типы-параметры в дженерик методе, тут нет никаких аллокаций и кастов и, скорее всего, весь код "аппендеров" будет заинлайнен JIT'ом.

JIT это значит нужно на рантайме что то инлайнить куда то

Может, сможете предложить хорошую замену? :D

C++, то что пишется в статье выглядит там просто как

a + b

И никакого джита и рантайм оверхеда

То есть, вместо "jit оверхеда" предлагается язык, созданный для отстрела ног? Спс, но я лучше перейду с C# на Python, чем на это недоразумение из 80-х, даже создатель которого рекомендует писать на чем-то другом. Или останусь в мире оверхеда, зато с GC и отсутствием 10 способов выделить и освободить память, половина из которых объявлена ересью.

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

Ничего говорить не будешь, просто потому что тебе нечего сказать. Зачем ты тогда сюда зашёл? Чтоб неконструктивный срач устроить?
Кстати, судя по комментариям в других топиках, ты любитель пополивать другие языки, особенно языки с gc (кстати, почему у тебя так сильно с gc горит?). Неадекват одним словом.

Тут неадекватность только ты своим сообщением показываешь

я хоть на C++ и не пишу уже лет 8, но меня удивляет, как джависты/шарписты, которые имеют представление о C++ на уровне универских лаб, цепляются к этой памяти и своему GC, как будто других ресурсов, типа сокетов, файловых дескрипторов итд, у них нет. Лет 100 уже в плюсах никто памятью вручную не рулит, есть RAII. Даже в Scala typeclass-ы используются, а в плюсах есть такая вещь как концепты. Плюсы вообще самый гибкий язык со статической типизацией из тех, с которыми я работал, достаточно почитать Александреску "Как я поел грибов современное проектирование на C++"

Вчера настроения не было писать, но да, однажды я программисту на Java рассказал как на самом деле устроено "управление памятью" в С++(просто как работают деструкторы и область видимости) и он не мог поверить, что вот так вот просто можно выкинуть гц, а ещё менеджить огромное количество других ресурсов с помощью этого механизма

А потом эти же программисты учат все реализации гц, чтобы знать это и учитывать, чтобы код выполнялся за конечное время и пишут int a,b вместо int a; int b, потому что так лучше оптимизирует jit.

Вообще это громадный миф, что у jit есть какая то там информация которая ему что-то позволяет лучше оптимизировать, фактически java/C# и тд неоптимизируемые языки силу того как они работают, если посмотреть на то что компилятор делает с С++ кодом конечно

Можно долбиться в байты, а можно делать дела и зарабатывать. За много лет .NET ни разу не подвёл, никаких проблем с GC не видывал. По удобству разработки и инструментария топ.

Извините "дрочить" на байты и процессорные тики, это отдельный узкий профиль. Как говорится, если действительно понадобится Си, или С++, да хоть брейнфак -- возьмём его.

Ох уж этот религиозный фанатизм GC/не-GC, ой да там RAII, ой а у .NET-а рефлексия и аспекты, и т.д. и т.п.

Я точно знаю одно. Разработка большого проекта аля учётная система, на С++ будет дороже на порядок, ещё и дольше. А будет ли ощутимый выигрыш? Я очень сомневаюсь, так как .NET ещё не был узким местом в моей практике нигде.

Это очередной миф, что в С++ обязательно надо долбиться в байты. Не надо.

На С++ сложнее научиться писать, но после того как умеешь - разработка ни разу не медленнее чем на любом другом языке, а может и быстрее, язык позволяет добиться любого уровня абстракции, в этом плане он гибче и си шарпа и джавы и питона и тд

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

А вы и правда считаете, что в мире инженеры тупые и им легко навязать какой-то фиговый инструмент? :)

Если бы на С++ разработка стоила бы дешево и позволяла достигать нужного уровня эффективности, я вас уверяю -- сегодня бы большинство писало на C++, заливать про тайные заговоры компаний не нужно. Тот же Microsoft вкладывается в разработку C++ постоянно, инструменты на высочайшем уровне. И что? Это очень хороший и уважаемый язык, но у него своя ниша.

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

Нужно вот такое, очень много и часто:

public record SomeData(double? Cost, int? Amount,...)

std::optional? Передавать какую-нибудь фигню типа -1 как отсутствие значения? Нет уж, увольте. Сами кушайте :)

Судя по фразам, легко делается вывод, что вы засели в своем cpp-болотце. Ой нехорошо, надо гибче быть и объективно сравнивать. А так как компетенций нет (в контексте огромных .NET-овских пластов знаний), то лучше избегать фанатизма.
У плюсовиков это пассивный навык - не считать других разработчиков за людей, так как они выстрадали свои годы опыта.)

UFO just landed and posted this here

в современных реализациях вышеупомянутых платформ JIT развернёт это как надо и вполне может быть что заинлайнит вызов метода.

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

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

В реальном коде склейки, плюсы, аппенды и прочие конкатинации работают в типе класса и принимают ОДИН аргумент типа класса и выдают свой же тип как результат. Зачем тут дженерик? Чтобы клеить все и вся не учитывая тип? Таких задач в жизни не бывает.

Ближе всего я вижу необходимость помечать классы как способные агреггироваться. Но в данном случае решение унаследоваться от абстрактного класса - это говёное решение. В реальной жизни классу уже есть от чего наследоваться, а для обозначения возможностей классов придумали интерфейсы. В таком случае не надо вот этих всех "мудростей", просто наследуем IPohooy<T> и реализуем метод интерфейса T Pohooy(T second). Всё

¯\_(ツ)_/¯

И как же сделать, так чтобы, например, string реализовывал IPohooy<T> ?

А почему не подходит такой вариант?

class Appender
{
    public T AppendItems<T>(T a, T b) where T : IAppendable<T> => a.Append(b);
    public int AppendItems(int a, int b) => a + b;
    public string AppendItems(string a, string b) => a + b;
}

Потому что если a==null неизбежно словишь exception. А в default(TAppendable).Append(a, b); можно обработать эту ситуацию.

class Appender
{
    public T AppendItems<T>(T a, T b) where T : IAppendable<T> => a is not null ? a.Append(b) : b;
    public int AppendItems(int a, int b) => a + b;
    public string AppendItems(string a, string b) => $"{a}{b}";
}

Так?

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

Каких именно типов? - Их может быть очень много.
Задача - иметь один интерфейс для конкатенации произвольных типов. А не городить по новой перегрузке на каждый тип.

Имею в виду вот такое

class Appender
{
    public T AppendItems<T>(T a, T b, Func<T, T, T> append) => append(a,b)
}

Т.е. вместо структуры с методом писать функцию и её передавать.

Ну если клиентский код может предоставить метод, который выполняет конкатенацию (Func<T,T,T>), то зачем нужен Appender класс? Это уже бесполезная игра с кодом.
API должен выглядеть просто, несмотря на то, что там будет 100500 потомков, реализующих Append.

Если клиентский код может предоставить структуру с методом, то может предоставить и метод)

Вообще в ООП мире это называется паттерн стратегия или policy, тут ничего нового.

Это все верно, но только потому, что в итоге получилась такая реализация и тип операции передается явно, поэтому в многих случаях этот код можно заменить на более привычные вещи. Полноценно это можно сделать сейчас только для своих типов с помощью static abstract методов в интерфейсах, тогда достаточно указать что T : IAppendable<T>.

Конечно, есть вариант решить задачу «в лоб» — писать перегрузку на каждый тип данных, однако хотелось бы заставить компилятор помогать нам, не создавая 100500 методов.

Т.е. вместо 100500 методов вы предлагаете создать 100500 реализаций абстрактного класса? В чем профит?

Спасибо за статью.

> Конечно, есть вариант решить задачу «в лоб» — писать перегрузку на
каждый тип данных, однако хотелось бы заставить компилятор помогать нам,
не создавая 100500 методов.

Но в разве нам тогда не нужно будет создавать 100500 классв AppendableTYPE?
Пока не могу понять, когда какой полиморфизм лучше использовать.

Да, прекрасно знаю об этом, однако прикрепил в конец статьи proposals, которые некоторые рассматривали как альтернативу для решения задачи обобщения алгоритмов, в том числе в обсуждении Generic Math в GitHub.

К сожалению, при ФП подходе придётся крафтить что-то вроде Scala implicits, а этого никто в здравом уме конечно делать не будет.
Поэтому, для C# был избран другой путь, как мне кажется более подходящий.

Так как позднего связывания здесь не может быть, то можно всё переписать на статику:

Console.WriteLine(Appender.AppendItems<AppendableInt, int>(1, 2));
Console.WriteLine(Appender.AppendItems<AppendableString, string>("1", "2"));

interface IAppendable<T>
{
    abstract static T Append(T a, T b);
}

struct AppendableInt : IAppendable<int>
{
    public static int Append(int a, int b) =>
        a + b;
}

struct AppendableString : IAppendable<string>
{
    public static string Append(string a, string b) =>
        $"{a}{b}";
}

static class Appender
{
    public static T AppendItems<TAppendable, T>(T a, T b)
        where TAppendable : IAppendable<T> =>
        TAppendable.Append(a, b);
}

Окей, полугруппа есть, моноид считай есть. Функтор тоже понятно как сделать. А аппликативный функтор получится?

Sign up to leave a comment.