Pull to refresh

Comments 15

Либо через SFINAE, те же решения — вид сбоку

А в чём отличие? Полностью идентичный код.

Спасибо, поправил

"Здесь мы явно говорим, — эта функция существует только для тех типов T, которые удовлетворяют концепту std::equality_comparable, и если попытаться вызвать её с типом, у которого нет оператора ==, компилятор не будет пытаться «протащить» нас внутрь шаблона, а сразу сообщит: ограничение не выполнено — данный тип не является сравнимым на равенство."

Очевидно какая-то попытка получить аналог трейтов из Rust, аля PartialEq, только в отсутствие сильной типизации на уровне компилятора прикрутить типы для типов выглядит как костыль

Тут просто важно напомнить, откуда всё это взялось. Плюсы все же очень старый язык (40+?) и он десятилетиями развивался так, чтобы ничего не ломать из уже написанного кода, ну и он тоже из ниоткруда не появился, а взял часть сях, часть smalltalk, tcl и чего там еще было в начале, поэтому он не может просто взять и «переделать систему типов заново», вы банально все сломаете и даже ваша кошка будет смотреть на вас осуждающе. Поэтому все новые штуки, вроде концептов concepts, приходится аккуратно надстраивать поверх старых шаблонов, SFINAE и прочего исторического багажа и ничего с этим не поделать. Может из-за этого они иногда выглядят как костыли, хотя по сути это эволюция.

Rust оказался, кмк, в куда более удобной позиции, поскольку стартовал с чистого листа. Можно было сразу сказать: вот у нас traits, вот тут такие правила, вот вам такая строгая модель типов и никаких компромиссов ради кода, написанного дцать а то и больше лет назад, поэтому всё выглядит «правильно».

При этом rust на самом деле очень много взял из C++, тотже RAII, zero-cost abstractions, общее мышление про производительность, но он смог взять эти идеи уже в отшлифованном виде и встроить их в язык сразу, а не задним числом и не через три п.... извините за мой французский.

Так что концепты в плюсах это не попытка догнать rust, а попытка как-то наконец-то официально оформить то, чем люди пользовались годами, если не десятилетиями, через enable_if, type traits и прочие трюки. Ну да, выглядит менее элегантно, но работает и не ломает экосистему.

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

В принципе у Вас здоровое мнение, ничего плохого не вижу, проблемой плюсов тоже считаю легаси, но взгляните на Си, они хоть и имеют легаси куда большую, я бы предпочтитал писать на них - потому что не метались за совершенное, я открываю С++ теряюсь в их glvalue, xvalue, prvalue, одна move-семантика чего стоит, у вас на руках была нормальная move-семантика, нет нужно изобретать свою, лишь бы работало старое, дальше initialization list, что это? В каких скобках {} или () какой из убойного набора конструкторов вызовется, ну честно, какие-то гикки до хрипоты спорят... Как на этом писать, в Rust невозможны вопросы "что выведет эта программа", там все инструкции явные, сильная, статическая, строгая типизация, никаких неявных преобразований, что написано то и будет

в Rust невозможны вопросы "что выведет эта программа", там все инструкции явные

Думаю вы сильно ошибаетесь считая что в Rust все определенно ясно. Да и Rust вроде бы не делает на этом упор как Zig.

Пара примеров неочевидных вещей:

Загадка. Одна из этих строк не скомпилируется. Какая?

let a1: _ = [b"a", b"a" as &[u8]];
let b1: _ = [b"a" as &[u8], b"a"];
let a2: [_; 2] = [b"a", b"a" as &[u8]];
let b2: [_; 2] = [b"a" as &[u8], b"a"];
let a3: [&[u8]; 2] = [b"a", b"a" as &[u8]];
let b3: [&[u8]; 2] = [b"a" as &[u8], b"a"];

Имеете доступ к структуре за иммутабельной ссылкой, но хотите мутировать ее поле? Отрицаете любые авторитеты и хотите назло маме отморозить уши? Вас спасет баг rustc, заставляющий его автодополнять unsafe перед фигурными скобками:

struct Struct {
    field: i32,
}

fn mutate_behind_immutable_reference(r: &Struct) {
    let r = &mut { r.field };
    *r = 123;
}

И никакой borrow checker вам больше не помеха!

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

Примеры взяты из https://t.me/alisa_rummages
Там еще парочка есть

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

Превращения неизменяемой ссылки в изменяемую тут нет, как и автодополнения unsafe. В приведённом вами коде создаётся ссылка на временный объект. Но более понятным код от этого, увы, не становится.

ничего с этим не поделать

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

Вы не один это видите - это понимают вообще все, в том числе и комитет (я както говорил на конференции с @antoshkka об этом, там работают очень умные люди, которые прекрасно видят и технический долг и архитектурные проблемы языка) Радикальный разрыв тут просто невозможен, пока язык реально используется в проде, и именно поэтому вместо красивого перезапуска мы видим concepts, modules и constraints, в виде медленных шажков. Разбивка по файлам, о которой Вы сказали и TU это чисто про генерацию кода, а не про семантику языка (name lookup, overload resolution, правила шаблонов, ADL, ODR, ABI) должно быть одинаковым во всей программе, иначе компоновка будет давать разные результаты при каждой перекомпиляции (это один из моментов), если ввести разные модели языка, условно старую и новую, то у нас отваливается ODR (тут вам больше ребята с конференций расскажут). И вы забываете про вендоров, если ктото из большой тройки говорит - нет, мы не можем это сделать, комитет под козырек и откладывает на следующий стандарт.

В Раст есть блоки unsafe. Почему нельзя и в С++ так мягко перезапустить, введя блоки, внутри которых уже идёт С++2 с перезапущенным синтаксисом?

на самом деле не поделать, потомучто, обратная совместимость, Раст пользуется миром с/с++, я по началу тоже думал всё просто, поэтому ввели концепты, но модели исполнения кода совершенно разные, образно у нас есть Форт на стероидах, и прямое исполнение

проблема если учесть нового игрока Раст звучит теперь так, надо изменить неизменяемое, из-за модели исполнения Раста, это практически невозможно

Раст кстати проще С++, из-за доказательств перед исполнением, Раст практически функционален как мне кажется, тут не совсем даже синглтон как в С++, оно вроде похоже на синглтон из мира С++, но тут нормально так сделали, что даже не чувствуется тех проблем ), тем кому не нравятся синглтоны и зависимые структуры данных, даже не знаю, как в стиле ООП писать на Раст

потестил Раст всё в одной структурке компактно новейший Opengl, новейшие воксели )

но кстати если забить на Раст и подумать о Хаскель, то многое пофиксили поидее уже давно, правда я не смотрел как там пишут библиотеки, тоже наверно бинды, над низкоуровневыми интерфейсами

да и редактор Zed, оказался вообще клёвым ), такими темпами Раст действительно становится удобным инструментом, семантика мув тут просто классно работает

Всё верно. Туториал хороший, но я тут в тысячный раз восславил Кнута за своё решение несколько лет назад перейти на Rust.

Я даже на секунду поверил про совместимость. Но нет, MSVC 2022, cmake, gcc, Clang не могут собрать простой код написанный на c++ версии 1985 года. Например, они не знают откуда брать <stream.h> поддержка которого была удалена.

Пример кода, первое что в голову пришло
#include <stream.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

char* digit_names[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };

main(int argc, char* argv[])
{
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " <filename>\n";
        return 1;
    }
    char* in_path = argv[1];
    FILE* fin = fopen(in_path, "r");
    if (fin == 0) {
        cerr << "Error: File " << in_path << " not found or cannot be opened.\n";
        return 1;
    }
	
    int name_len = strlen(in_path) + 7;
    char* out_path = new char[name_len]; 
    strcpy(out_path, in_path);
    strcat(out_path, ".fixed");

    FILE* fout = fopen(out_path, "w");
    if (fout == 0) {
        cerr << "Error: Cannot create output file " << out_path << "\n";
        fclose(fin);
        delete out_path;
        return 1;
    }
    cout << "Processing file: " << in_path << "\n";
    cout << "Output file: " << out_path << "\n";

    int count = 0;
    int c;

    while ((c = fgetc(fin)) != EOF) {
        if (isdigit(c)) {
            int index = c - '0';
            fputs(digit_names[index], fout);
            count++;
        } else {
            fputc(c, fout);
        }
    }
    fclose(fin);
    fclose(fout);
    delete out_path; 
    cout << "Done. Replaced " << count << " digits.\n";
    return 0;
}

Ну какой же это Rust, это Haskell :)

Sign up to leave a comment.

Articles