LINUX.ORG.RU

C++20 и 2D Graphics

 ,


0

9

Исходник: https://isocpp.org/files/img/wg21-timeline-2017-11.png

Оказывается, все проблемы C++ уже решены, и теперь можно приступать к самой важной части системного языка - 2D графике.

Вопрос: что за безумие происходит в комитете C++? Зачем системному языку, да и вообще любому языку, 2D графика в std? Тем более, по слухам, они собираются использовать убогий cairo.

Из подобных языков приходит в голову только tcl/tk и red.

★★★★★

Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от anonymous

Нормальный профессиональный подход.

переписали пару сервисов на расте

С чего переписывали?

Virtuos86 ★★★★★
()
Ответ на: комментарий от anonymous

Йопь. И эти люди что-то про йебанутость синтаксиса плюсов заявляют?

Ну я, например, ничего особо плохого не вижу. Но в целом рабочий код на Rust выглядит достаточно перегруженным и, конечно, никакого выигрыша в размере кода не дает. Наоборот, достаточно тривиальные вещи преобразуются в пачку ::new, Some, unwrap. Видно, что не хватает перегрузки функций и потому в тех же ::new пишется больше чем можно было бы. Вот такой вот код, например, тоже специфичен именно для Rust и такое вряд-ли можно встретить в других языках:

let input = msg.get("text").unwrap().as_str().unwrap().to_owned();
anonymous
()
Ответ на: комментарий от Virtuos86

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

Чтоб писать меньше кода, вот вполне себе реальный код из Servo:

        Some(Rect::new(Point2D::new(x as f32, y as f32),
                       Size2D::new(w as f32, h as f32)))

В С++ это было бы:

Rect(x, y, w, h)

Потому-что неявный каст в optional и несколько конструкторов на выбор.

anonymous
()
Ответ на: комментарий от anonymous

Вот тебе ответ, зачем полезен отдельный impl:

mod foo {
    pub struct AlienStruct {
        pub n: i32
    }

    impl AlienStruct {
        pub fn alien_method() {}
    }
}

impl foo::AlienStruct { // Решил зопелить недостающий метод к типу из подключенного модуля
    fn my_cool_method() {}
}

Virtuos86 ★★★★★
()
Ответ на: комментарий от tailgunner

С этой же сигнатурой конструктора - не было бы.

«несколько конструкторов на выбор», что в С++ норма. А в Rust нет ни конструкторов, ни перегрузки, потому и пишут так. Можно, конечно, было бы добавить Rect::new_xywh, но это тоже не самое прямое решение.

anonymous
()
Ответ на: комментарий от Virtuos86

Вот тебе ответ, зачем полезен отдельный impl:

Согласен, но в Swift (раз уж тут tailgunner) есть нормальные классы и дополнительно extension, который делает ровно тоже самое и даже больше. И вот именно в таком виде это выглядит и удобно и раширяемо.

anonymous
()
Ответ на: комментарий от anonymous

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

Чтоб писать меньше кода, вот вполне себе реальный код из Servo:

        Some(Rect::new(Point2D::new(x as f32, y as f32),
                       Size2D::new(w as f32, h as f32)))

Кто-то выше правильно писал про From. Попроще выглядело бы так:

        Some(Rect::from((x, y), (w, h))

Virtuos86 ★★★★★
()
Ответ на: комментарий от anonymous

unwrap

В нормальном коде его нет.

не хватает перегрузки функций

Не хватает...

Вот такой вот код, например, тоже специфичен именно для Rust и такое вряд-ли можно встретить в других языках:

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

В обычном C++, в котором нет string_view и аналогов, будет тупо копирование строк туда-сюда. Нехорошо. Rust заставляет думать об аллокациях.

Ну и приведенный вам код можно встретить только при работе с fs, ибо OsString - это просто контейнер, без методов. Увы и ах.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от anonymous

В С++ это было бы:

А чё сразу не { x, y, w, h }? Если уж хотите тупить, так приводите реальные аналоги, ака:

Rect(Point2D(x, y), Size2D(w, h));

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Вот тебе ответ, зачем полезен отдельный impl:

Согласен, но в Swift (раз уж тут tailgunner) есть нормальные классы и дополнительно extension, который делает ровно тоже самое и даже больше. И вот именно в таком виде это выглядит и удобно и раширяемо.

Не уговаривай, про Swift читать не пойду.

Да, Rust — точно не про компактный код, это всё пустое дело с этим фактом спорить.

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Да, Rust — точно не про компактный код, это всё пустое дело с этим фактом спорить.

Вы видели примеры использования std::variant?

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

А чё сразу не { x, y, w, h }?

Потому-что ты не знаешь С++, и еще раз это подтверждаешь.

Если уж хотите тупить, так приводите реальные аналоги, ака

Еще раз - в С++, да и не только, нет проблемы Rust'а в виде отсутствия перегрузки функций. Вон ты Qt ковыряешь, посмотри на конструкторы QRect - их большего одного, просто потому-что так можно.

anonymous
()
Ответ на: комментарий от anonymous

Потому-что ты не знаешь С++, и еще раз это подтверждаешь.

class Rect
{
public:
    Rect(int ax, int ay, int aw, int ah)
        : x(ax), y(ay), w(aw), h(ah)
    {}

    int x;
    int y;
    int w;
    int h;
};

Rect myFunc()
{
    return { 1, 2, 3, 4 };
}

int main()
{
    auto r = myFunc();
}

ЧЯДНТ?

проблемы Rust'а в виде отсутствия перегрузки функций

Это проблему я не отрицаю. Но у неё есть «решения», о которых вы, видимо, не знаете. И это трейт From.

Проблема в том, что это сложно назвать проблемой. Короче ли C++ версия - да. Надежнее ли - нет.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Не вижу ссылку на винду, андроид и тд.

Для классов, которых в Rust все-равно нет.

Для того, для чего захочется компилятору.

RazrFalcon ★★★★★
() автор топика
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Если отстаивать утверждение, что Rust лаконичен, то надо и сравнивать его не с дремучим чудовищем C++, а с более подходящими конкурентами, лидирующими в этом аспекте в сходной весовой категории (то есть чей синтаксис должен покрывать сравнимые смысловые конструкции).

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Всю тему я сравнивал его исключительно с С++. Сравнивать его с тем же питоном мне бы и в голову не пришло.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

ЧЯДНТ?

Забыл про каст к optional.

Это проблему я не отрицаю. Но у неё есть «решения», о которых вы, видимо, не знаете. И это трейт From.

Видимо не знаю, хотя трейт From применял. Можно пример, как через него можно сделать два конструктора для Rect?

anonymous
()
Ответ на: комментарий от RazrFalcon

Не вижу ссылку на винду, андроид и тд.

А зачем? Пишешь на линуксе, собираешь под что надо:

https://github.com/apple/swift/blob/master/utils/swift_build_support/swift_bu...

Для того, для чего захочется компилятору.

Например для чего?

anonymous
()
Ответ на: комментарий от Virtuos86

Если сравнивать без C++ и Java - да, многословный.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от Virtuos86

а с более подходящими конкурентами, лидирующими в этом аспекте в сходной весовой категории

Ну и какие у Rust-а конкуренты в этой нише, кроме C++ и Ada?

eao197 ★★★★★
()
Ответ на: комментарий от quantum-troll

Замечательно. А как различить, к примеру, `Color::from_rgb` и `Color::from_hsl`?

А зачем их различать?

http://doc.qt.io/qt-5/qcolor.html

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

use std::fs::OpenOptions;

let file = OpenOptions::new().read(true).open("foo.txt");

Хотя даже без перегрузки прямее было бы сделать:

let file = File::open_with_options("foo.txt", OpenOptions::new().read(true))
anonymous
()
Ответ на: комментарий от anonymous
#[derive(Debug)]
struct Point2D(usize, usize);

#[derive(Debug)]
struct Size2D(usize, usize);

#[derive(Debug)]
struct Rect {
    point: Point2D,
    size: Size2D
}

impl Rect {
    fn new(point: Point2D, size: Size2D) -> Self {
        Self { point, size }
    }
}

impl std::convert::From<(usize, usize, usize, usize)> for Rect {
    fn from(rect: (usize, usize, usize, usize)) -> Self {
        Self { point: Point2D(rect.0, rect.1), size: Size2D(rect.2, rect.3) }
    }
}

fn main() {
    let (x, y, w, h) = (0, 1, 2, 3);
    let rect1 = Rect::new(Point2D(x, y), Size2D(w, h));
    let rect2 = Rect::from((x, y, w, h));
    println!("rect1 = {:?}\nrect2 = {:?}", rect1, rect2);
}

https://play.rust-lang.org/?gist=49280f8c9c27cc658ffd7ed1f4592f09&version...

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от anonymous

Забыл про каст к optional.

У меня нет C++17 компилятора, чтобы проверить.

Можно пример, как через него можно сделать два конструктора для Rect?

Один, а не два. Классическое решение через кортежы:

#[derive(Clone,Copy)]
struct Point {
    x: f64,
    y: f64,
}

#[derive(Clone,Copy)]
struct Size {
    w: f64,
    h: f64,
}

#[derive(Debug)]
struct Rect {
    x: f64,
    y: f64,
    w: f64,
    h: f64,
}

impl From<(f64, f64, f64, f64)> for Rect {
    fn from(v: (f64, f64, f64, f64)) -> Self {
        Rect {
            x: v.0,
            y: v.1,
            w: v.2,
            h: v.3,
        }
    }
}

impl From<(Point, Size)> for Rect {
    fn from(v: (Point, Size)) -> Self {
        Rect {
            x: v.0.x,
            y: v.0.y,
            w: v.1.w,
            h: v.1.h,
        }
    }
}

impl Rect {
    pub fn new<T>(value: T) -> Self
        where Rect: From<T>
    {
        value.into()
    }
}

fn main() {
    println!("{:?}", Rect::new((1.0, 2.0, 3.0, 4.0)));
    
    let point = Point { x: 1.0, y: 2.0 };
    let size = Size { w: 3.0, h: 4.0 };
    println!("{:?}", Rect::new((point, size)));
 
    let rect: Rect = (1.0, 2.0, 3.0, 4.0).into();
    println!("{:?}", rect);
    
    let rect: Rect = (point, size).into();
    println!("{:?}", rect);
}

Было бы это короче в C++ - безусловно.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от anonymous

OpenOptions::new().read(true).open("foo.txt");

Это скорее про отсутствие именованных параметров (как в питоне), а не перегрузки.

File::open_with_options("foo.txt", OpenOptions::new().read(true))

Можно, но зачем?

quantum-troll ★★★★★
()
Ответ на: комментарий от anonymous

потому рождаются такие уродства

Вы никогда не видели builder pattern?

Хотя даже без перегрузки прямее было бы сделать:

И чем ваш вариант лучше, кроме того, что он длиннее? Мы же тут про лаконичность говорим?

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Один, а не два

А, ну я так было и подумал. Ну ты сам понимаешь почему так никто не делает.

anonymous
()
Ответ на: комментарий от anonymous

Почему не делают? Очень даже делают. Как уже выше писал знатный спец по C++ - одни раз реализовал и используешь. Тут тоже самое. В пользовательском коде такое никто писать не будет, а вот упростить API либы - самое оно. Главное не злоупотреблять.

RazrFalcon ★★★★★
() автор топика
Ответ на: комментарий от eao197

в сходной весовой категории

в этой нише

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

Virtuos86 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Вы никогда не видели builder pattern?

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

И чем ваш вариант лучше

Тем, что open и open_with_options были бы рядом в одном месте, как и полагается.

anonymous
()
Ответ на: комментарий от RazrFalcon

Вы никогда не видели builder pattern?

Я видел другой паттерн. Как-то так.

void OnError(SomeType message) 
{
...
connection.send_ansver(Body {
    Img { "content/heap.png" }, 
    P {
       Font { 
           Color {"red"},
           message
       }
    },
    Img { "content/tail.png" }, 
    Style { "content/copyright" }
});
}
anonymous
()
Ответ на: комментарий от RazrFalcon

По ссылке как раз явные setCmyk, setRgb, setHsv и тд. Страннонет, что они их через конструктор не сделали.

В данном случае ты путаешь from и set, set меняет уже существующий объект.

anonymous
()
Ответ на: комментарий от Virtuos86

Сравнение ЯП без GC и с GC изначально некорректно, вне зависимости от того, компилируемые языки или нет. Соответственно, что еще есть в современном мире из статически-типизируемых нативных языков без GC, что хоть сколько-нибудь широко использовалось?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Соответственно, что еще есть в современном мире из статически-типизируемых нативных языков без GC, что хоть сколько-нибудь широко использовалось?

Swift :) С одной стороны практически только на маке, то зато явно популярнее раста.

anonymous
()
Ответ на: комментарий от Virtuos86

Думаю, сравнение лаконичности Fortran-а и Rust-а было бы интересным. И не в пользу обоих :)

Тут выше подсказали Swift. Так что выбор для сравнения небольшой: С++, Ada, Swift. Может еще какой-нибудь FreePascal.

Вы точно думаете, что Rust многословнее многих из этого списка?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Раз есть Swift, можно еще и ObjC добавить.

Вы точно думаете, что Rust многословнее многих из этого списка?

Еще раз. Я думаю, что Раст многословен сам по себе. Те же unwrap'ы, as'касты, лайфтаймы, спорадические пляски с владением, вынуждающие использовать воркэраунды, два типа строк. Субъективные ощущения превалируют, конечно.

Virtuos86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.