Команда Rust рада представить выпуск Rust 1.21.0. Rust — это системный язык программирования, нацеленный на скорость, безопасность и параллельное выполнение кода.


Если у вас установлена предыдущая версия Rust, для обновления достаточно выполнить:


$ rustup update stable

Если же у вас еще не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта. С подробными примечаниями к выпуску Rust 1.21.0 можно ознакомиться на GitHub.


Что вошло в стабильную версию 1.21.0


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


Первое изменение касается литералов. Рассмотрим код:


let x = &5;

В Rust он аналогичен следующему:


let _x = 5;
let x = &_x;

То есть 5 будет положено в стек или возможно в регистры, а x будет ссылкой на него.


Однако, учитывая, что речь идет о целочисленном литерале, нет причин делать значение таким локальным. Представьте, что у нас есть функция, принимающая 'static аргумент вроде std::thread::spawn. Тогда вы бы могли использовать x так:


use std::thread;

fn main() {
    let x = &5;

    thread::spawn(move || {
        println!("{}", x);
    });
}

Этот код не соберется в прошлых версиях Rust'а:


error[E0597]: borrowed value does not live long enough
  --> src/main.rs:4:14
   |
4  |     let x = &5;
   |              ^ does not live long enough
...
10 | }
   | - temporary value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

Из-за локальности 5, ссылка на него тоже живет слишком мало, чтобы удовлетворить требованиям spawn.


Но если вы соберете это с Rust 1.21, оно заработает. Почему? Если что-то, на что создана ссылка, можно положить в static, мы могли бы "обессахарить" let x = &5; в нечто вроде:


static FIVE: i32 = 5;

let x = &FIVE;

И раз FIVE является static, то x является &'static i32. Так Rust теперь и будет работать в подобных случаях. Подробности смотрите в RFC 1414, который был принят в январе 2017, но начинался еще в декабре 2015!


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


RLS теперь может быть установлен через rustup вызовом rustup component add rls-preview. Много полезных инструментов, таких как RLS, Clippy и rustfmt, все еще требуют ночной Rust, но это первый шаг к их работе на стабильном канале. Ожидайте дальнейших улучшений в будущем, а пока взгляните на предварительную версию


Теперь об улучшениях документации. Первое: если вы посмотрите на документацию модуля std::os, содержащего функционал работы с операционными системами, вы увидите не только Linux — платформу, на которой документация была собрана. Нас долго расстраивало, что официальная документация была только для Linux. Это первый шаг к исправлению ситуации,
хотя пока что это доступно только для стандартной библиотеки, а не для любого пакета (crate). Мы надеемся исправить это в будущем.


Далее, документация Cargo переезжает! Исторически документация Cargo была размещена на doc.crates.io, что не следовало модели выпусков (release train model), хотя сам Cargo следовал. Это приводило к ситуациям, когда какой-то функционал скоро должен был "влиться" в ночной Cargo, документация обновлялась, и в течение следующих 12 недель пользователи думали, что все работает, хотя это еще не было правдой. https://doc.rust-lang.org/cargo будет новым домом для документации Cargo, хотя сейчас этот адрес просто перенаправляет на doc.crates.io. Будущие выпуски переместят настоящую документацию Cargo, и тогда уже doc.crates.io будет перенаправлять на doc.rust-lang.org/cargo. Документация Cargo уже давно нуждается в обновлении, так что ожидайте еще новостей о ней в скором будущем!


Наконец, до этого выпуска у rustdoc не было документации. Теперь это исправлено: добавлена новая книга "rustdoc Book", доступная по адресу https://doc.rust-lang.org/rustdoc. Сейчас эта документация очень примитивна, но со временем она улучшится.


Подробности смотрите в примечаниях к выпуску.


Стабилизации в стандартной библиотеке


В этом выпуске не так много стабилизаций, но есть кое-что, очень упрощающее жизнь: из-за отсутствия обобщения относительно целых чисел (type-level integers), массивы поддерживали типажи только до размера 32. Теперь это исправлено для типажа Clone. Кстати, это же вызывало много ICE (внутренних ошибок компилятора), когда тип реализовывал только Copy, но не Clone.
Для других типажей недавно был принят RFC об обобщении относительно целых чисел, который должен исправить ситуацию. Это изменение еще не реализовано, но подготовительные работы уже ведутся.


Затем был стабилизирован Iterator::for_each, дающий возможность поглощать итератор ради побочных эффектов без for цикла:


// старый способ
for i in 0..10 {
    println!("{}", i);
}

// новый способ
(0..10).for_each(|i| println!("{}", i));

Какой из способов лучше зависит от ситуации. В коде выше for цикл прост, но, если вы выстраиваете цепочку итераторов, версия с for_each может быть понятнее:


// старый способ
for i in (0..100).map(|x| x + 1).filter(|x| x % 2 == 0) {
    println!("{}", i);
}

// новый способ
(0..100)
    .map(|x| x + 1)
    .filter(|x| x % 2 == 0)
    .for_each(|i| println!("{}", i));

Rc<T> и Arc<T> теперь реализуют From<&[T]> where T: Clone, From<str>, From<String>, From<Box<T>> where T: ?Sized, и From<Vec<T>>.


Стабилизированы функции max и min типажа Ord.


Стабилизирована встроенная функция (intrinsic) needs_drop.


Наконец, был стабилизирован std::mem::discriminant, позволяющий вам узнать активный вариант перечисления без использования match оператора.


Подробности смотрите в примечаниях к выпуску.


Функционал Cargo


Помимо вышеупомянутых изменений документации Cargo в этом выпуске получает большое обновление: [patch]. Разработанная в RFC 1969, секция [patch] вашего Cargo.toml может быть использована, когда вы хотите заменить части вашего графа зависимостей. Это можно было сделать и раньше, посредством [relace]. Если коротко, то [patch] это новый и более удобный [replace]. И хотя у нас нет планов убирать или объявлять устаревшим [replace], вам скорее всего стоит использовать именно [patch].


Как же работает [patch]? Допустим, у нас есть такой Cargo.toml:


[dependencies]
foo = "1.2.3"

Так же наш пакет (crate) foo зависит от пакета bar, и мы нашли ошибку в bar. Чтобы проверить это, мы скачиваем исходный код bar и обновляем наш Cargo.toml:


[dependencies]
foo = "1.2.3"

[patch.crates-io]
bar = { path = '/path/to/bar' }

Теперь при выполнении cargo build будет использована наша локальная версия bar, а не версия из crates.io, от которой на самом деле зависит foo.


Подробности смотрите в документации.


Также:



Подробности смотрите в примечаниях к выпуску.


Разработчики 1.21.0


Множество людей участвовало в разработке Rust 1.21. Мы не смогли бы этого добиться без участия каждого из вас. Спасибо!


От переводчика: Благодарю sasha_gav и vitvakatu за помощь в переводе

Комментарии (26)


  1. beduin01
    17.10.2017 09:15
    -6

    let x: &'static u32 = &0;

    Rust с каждой версией все более и более уродским становится.

    Вот хороший пример читаемости синтаксисов:
    Go:
    func typeList(arch *TFile,
          offset uint32, parseDecl bool) []BStr {

    C++
    std::vector<std::string> typeList(TFile* arch,
            off_t offset, bool parseDecl) {


    Rust:
    fn typeList<'a>(arch: &'a TFile<'a>,
          offset: u32, parseDecl: bool) -> Vec<&'a bstr> {


    D:
    string[] typeList(File arch, size_t offset, bool parseDecl) {


    1. ozkriff Автор
      17.10.2017 09:22
      +1

      Rust с каждой версией все более и более уродским становится.

      А в чем отличие читаемости rust 1.21 от 1.20?


      Вот хороший пример читаемости синтаксисов:

      О.о Теплое с мягким.


      1. beduin01
        17.10.2017 09:28
        -3

        >А в чем отличие читаемости rust 1.21 от 1.20?
        Да ничем. Она отсутствует.


    1. mayorovp
      17.10.2017 09:28
      +2

      Вообще-то, в Rust приведенная вами строчка при желании сохранить читаемость пишется как let x = &0;. Но даже в таком виде она на самом деле является бессмысленной, так никто не пишет; в реальности эта фича нужна при применении каких-нибудь обобщенных алгоритмов к примитивам.


    1. pftbest
      17.10.2017 09:31
      +2

      Вам на ЛОРе уже писали что сравнение неверное, эквивалентный код будет


      fn typeList(arch: &TFile, offset: u32, parseDecl: bool) -> Vec<String> {

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


      fn typeList<'a>(arch: &'a TFile, offset: u32, parseDecl: bool) -> Vec<&'a str> {


      1. phponelove
        17.10.2017 11:12
        -1

        Вам на ЛОРе уже писали что сравнение неверное, эквивалентный код будет

        Не верно. На лоре в первых же сообщениях пример был изменён.

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

        Манипуляция. А так будет ещё короче:

        fn typeList<'a>(a: &'a TFile, b: u32, c: bool) -> Vec<&'a str> {

        И?

        То, что мы нормальные имена заменили на a и назвали это «нормальным» — это ничего не меняет. А если туда добавить generics? А если добавить ещё один лайфтайм? Во что превратиться это?


        1. ozkriff Автор
          17.10.2017 11:26
          +3

          Не верно. На лоре в первых же сообщениях пример был изменён.

          А можно тогда привести пример этого исправленного адекватного сравнения?


          А если туда добавить generics? А если добавить ещё один лайфтайм? Во что превратиться это?

          А синтаксис ржавчины тут причем? В любом языке при добавлении качественно отличающейся информации размер сигнатуры функции (да и любой другой записи) будет увеличиваться.


          Я так понимаю что придирка сводится к тому что ржавчина умеет явно выражать ВЖ, а большинство других языков — нет? Тогда, надо выбрать победителем питон и успокоиться.


          1. phponelove
            17.10.2017 14:05
            -3

            А можно тогда привести пример этого исправленного адекватного сравнения?

            Зачем вы пытаетесь создавать себе «пути к отступлению» вводя какие-то непонятные критерии, которых ранее не было?

            Подтверждение моим словам есть — www.linux.org.ru/forum/development/13699421#comment-13699478

            А синтаксис ржавчины тут причем?

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

            Не верно. В расте это дополнительный ахтунг, которого в другом языке(без лайвтаймов) не будет.

            Я так понимаю что придирка сводится к тому что ржавчина умеет явно выражать ВЖ, а большинство других языков — нет?

            Это не придирка. Раст ввёл в язык некую новую сущность, которая не бесплатна с т.з. читаемости и ой как не бесплатна. Да и синтаксис очень спорен — это как минимум.

            А люди почему-то выдают её за бесплатную. В этом и есть проблема.

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

            Это глупость. И почему — ниже так же объяснили на том же лоре.

            И ваш пример крайне показателен. Вы не спорите с тем, что явная типизация не бесплатна, а в ситуации с растом это не так. Тип — это свойство переменной, который не указывается явно в питоне. Точно так же лайвтайм — это такое же дополнительное свойство. Т.е. ситуация аналогичная, но в случае с растом у нас «всё так же»( что явно неправда), а в случае с питоном всё не так же.

            Таким образом питон < С++ < раст. Критерий ясен и понятен. С питоне только имя, в С++ имя и тип, в расте имя + тип + лайвтайм.

            Это явная манипуляция о которой я и говорил.


            1. ozkriff Автор
              17.10.2017 14:42
              +2

              Зачем вы пытаетесь создавать себе «пути к отступлению» вводя какие-то непонятные критерии, которых ранее не было?

              Потому что сравнение в первом комментарии этой темы очевидно бессмысленно — третьесортный толстый троллинг с лора — и тратить время на анализ подобного не хочется.


              А люди почему-то выдают её за бесплатную. В этом и есть проблема.
              И ваш пример крайне показателен. Вы не спорите с тем, что явная типизация не бесплатна, а в ситуации с растом это не так.

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


              Первый комментарий был про уродство ржавого синтаксиса — вот с этим я не согласен, я уверен что это просто вопрос привычки.


              Да и синтаксис очень спорен

              Обсуждений было много, лучше так никто и не предложил.


              В расте это дополнительный ахтунг, которого в другом языке(без лайвтаймов) не будет.

              … И там нет возможности выразить эту полезную в некоторых ситуациях информацию, разве нет?


              1. phponelove
                17.10.2017 15:06
                -5

                Потому что сравнение в первом комментарии этой темы очевидно бессмысленно — третьесортный толстый троллинг с лора — и тратить время на анализ подобного не хочется.

                Для вас всё неудобное троллинг. Очень удобно, не спорю.

                Я не вижу что бы кто-то в этой теме заявлял о полной бесплатности ВЖ для читателя кода.

                Выше, пожалуйста. Никто из ваших оппонентов не обязан что-то знать про ваш «язык». Приводят примеры и если что-то в них немного неверно написано, то их этого ничего не следует. Это ваша обязанность адаптировать примеры.

                А то получается как «будет то же самое» и всё очень удобное — можно посмеяться над автором, но суть примера не в этом. Об этом в том треде сообщили и я вам тут сообщил, что вы, благополучно, проигнорировали. Очень удобно, повторю.

                >> Явные ВЖ усложняют типы, только я считаю что это окупается более выразительной формальной семантикой — так и сам код понимать проще, и оптимизации дополнительные можно провести, и от кучи ошибок с памятью автоматически защищает.
                Вся эта «более выразительная» — ничего общего с объективностью не имеет. Это итак ясно из контекста.

                Наличие подобно в расте лишь следствие слабости компилятора и не более того. А все эти рассуждения об каких-то мистических оптимизациях ничего так же не стоят без примеров. Я их не видел, вы их не показали. Нет никаких оснований вам верить. Всё просто.

                Первый комментарий был про уродство ржавого синтаксиса — вот с этим я не согласен, я уверен что это просто вопрос привычки.

                Этим можно оправдать всё что угодно. Следует ли из этого что-то? Нет. Ваши слова значат не более чем его, либо чем мои. Никаких объективных свидетельств нету.

                Обсуждений было много, лучше так никто и не предложил.

                Из этого так же ничего не следует. Отсутствие предложения в какой-то определённой тусе мало что значит. Да и какое там могло быть обсуждение, если это просто рандомный символ на подобии *&. Что там остаётся? #@'? По мне так ' самое глупое из них. По причине 'a' ~= 'a.

                Да и странно как-то обсуждалось всё это. Был ГЦ, был другой синтаксис. Потом вдруг бам. ГЦ не стало, ГЦ стал не моден. Идеальный синтаксис выпилили и взяли крестовый.

                >>… И там нет возможности выразить эту полезную в некоторых ситуациях информацию, разве нет?
                Ещё раз. Она там только по причине слабости компилятора. Никакой новой информации она не даёт — она итак выводится из контекста.

                То же самое с автоматическим выводом типов. Оно не теряет типы. И нужно не для какой-то там неведомой «полезной информации», а чисто для ограничений, либо кастов всяких литералов в нужный тип.

                Если у меня есть функция (a) -> b {return c{a};}, где с хранит ссылку a, но при этом это компилятор сам вывести не может — это никакой новой информации мне не даёт, да и вообще не даёт.


            1. 0xd34df00d
              17.10.2017 19:47
              +1

              Притом, что в других языках никаких лайвтаймов нет и если в крестах есть 2 вида аргументов, то тут есть уже три.

              По значению, по указателю, по lvalue-ссылке, по rvalue-ссылке. Какие два вида из этих вы имели в виду?

              И это я ещё про шаблонную наркоманию не говорю.

              В расте это дополнительный ахтунг, которого в другом языке(без лайвтаймов) не будет.

              А в языке без статических типов вообще типов не будет. Щастье-то какое!

              Тип — это свойство переменной, который не указывается явно в питоне.

              Тип в питоне — это свойство объекта в рантайме, который скрывается за переменной. Статических типов там нет. К сожалению.

              Таким образом питон < С++ < раст. Критерий ясен и понятен. С питоне только имя, в С++ имя и тип, в расте имя + тип + лайвтайм.

              Во-первых, такой код сложнее поддерживать (где нет статических типов).
              Во-вторых, куда вы там впихнёте какой-нибудь хаскель, например?


        1. red75prim
          17.10.2017 11:34
          +2

          'a в данном случае никакого собственного смысла не несёт, единственная его функция — указать одинаковость времён жизни arch и возвращаемого значения. Поэтому нет никакого смысла придумывать для него длинное имя.


          Для сравнения, в Haskell аннотации типов обычно тоже однобуквенные: (a -> b) -> a -> b. Потому что нет никакого смысла писать (любойтип1 -> любойтип2) -> любойтип1 -> любойтип2. Так и здесь нет никакого смысла писать 'любое_подходящее_время_жизни_1


          1. phponelove
            17.10.2017 14:23
            -2

            'a в данном случае никакого собственного смысла не несёт, единственная его функция — указать одинаковость времён жизни arch и возвращаемого значения.

            Никакого собственного смысла имя типа в шаблонах не несёт, единственная его функция — указать одинаковость типов…

            Никакого собственного смысла переменная не несёт, единственная её функция — указать одинаковость значений…

            Ну и ключевое слово «в данном случае». А не в данном?

            >>Для сравнения, в Haskell аннотации типов обычно тоже однобуквенные
            И? Что же из этого следует? Т.е. вы мне предлагаете писать так: а<A, 'a, B, C>(arg0: &'a A, arg1: &'a B) -> &'a B? Либо как там у вас будет? Нет, спасибо.

            Потому что нет никакого смысла писать (любойтип1 -> любойтип2)

            Т.е. вместо (Container, Value) -> Iterator мне надо писать (a, b) -> c? Нет, спасибо. Проблема в том, что там не любой тип — любой тип никому не нужен.


            1. red75prim
              17.10.2017 15:56
              +3

              Для сравнения, в Haskell аннотации типов обычно тоже однобуквенные

              Что же из этого следует?

              Из этого следует, что не стоит напрягаться и придумывать описание для вещей, которые в описании не нуждаются. Переменные обычно связаны с семантикой выполняемых функцией действий, поэтому имеет смысл называть их так, чтобы семантика функции становилась яснее. Функции аннотаций времен жизни — связывание времен жизни различных переменных отношением равенства и задание отношения "живёт-дольше-чем" между двумя временами жизни. Как ни назови 'a, его значение будет "ссылка X живет столько же сколько ссылка Y", а это и так видно из кода.


              Требовать назвать время жизни осмысленней, примерно то же самое, что отказываться решать уравнение 2*x+4=0, пока вместо x не поставят "неизвестное_количество_яблок" или что-то в этом роде.


              Т.е. вместо (Container, Value) -> Iterator мне надо писать (a, b) -> c? Нет, спасибо. Проблема в том, что там не любой тип — любой тип никому не нужен.

              Это совершенно разные сигнатуры функций. В Haskell идентификаторы используемые в сигнатуре функции и начинающиеся со строчной буквы обозначают именно любой тип.


              В C++ это будет template<a,b,c> c func(std::pair<a,b> val){...} и Iterator func(std::pair<Container, Value> val) — разные вещи, в общем.


              Кстати, функция с сигнатурой (a,b) -> c довольно бессмысленна, так как может возвращать только bottom. Но это уже к обсуждению не относится.


              1. phponelove
                17.10.2017 17:25
                -1

                Требовать назвать время жизни осмысленней, примерно то же самое, что отказываться решать уравнение 2*x+4=0, пока вместо x не поставят «неизвестное_количество_яблок» или что-то в этом роде.


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


                Явное противоречие. Вы уж определитесь с тем — нужно ли вводить ассоциацию между значением и тем, что оно выражает, либо нет. А то в одном случае смысла нет, а в другом есть.

                Как ни назови 'a, его значение будет «ссылка X живет столько же сколько ссылка Y», а это и так видно из кода.

                Я уже давал вам вариации на тему, которые вы, благополучно, проигнорировали. Как не назови A, его значение будет «тип ссылки X является тем же, что у типа ссылки Y».

                Я могу попытаться найти какое-то рациональное зерно в ваших рассуждения и сформулировать его. Переменные — это отображение неких сущностей из реальной мира, либо каких-то внешних моделей. Есть модель тех же уравнений — там у x есть чёткое определение, только оно определённо где-то в рамках этой модели. И записывая 2x+4=0 вы просто используете x как экспорт из этой модели. И уже каждый знает что такое x.

                А вот если вы там напишите 2*g+4=0, то вы получите фейл. Т.к. вы привели банальный подлог.

                Поэтому, если мы считаем яблоки, то у нас и название переменных будут яблоки, а не x — x это некая обобщённая форма неизвестной. Как то же value. И использовать везде abc вместо яблок — это моветон.

                Тут имеет смысл только ссылка на то, что лайвтаймы — это про отношения ссылок/сущностей внутри самого языка. Мы не экспортируем что-то явно, либо по умолчанию( как в примере с x), а именно определяем их в определённом контексте.

                Но опять же — это тупиковый путь. open_file(string a); — почему подобное является моветоном? Ведь контекст явно определён. file, да и тип string из которого мы сразу узнаём искомое свойство файла, но. Это некрасиво, это глупо.

                Поэтому да, явно видно к чему привязан лайвтайм, но. Явно видно и то, что a = x * y. Но что дальше? По мне так лучше это назвать xy, пусть мы итак видим, что это x * y. Явно видно, что string a = file.name; Но что из этого следует? Да ничего, кроме того, что это явная глупость.

                То же самое с лайвтаймами. Смотря на 'a — я не понимаю что это и откуда взялось. Мне надо смотреть на полный контекст, который может быть не таким примитивным. Зачем? А незачем. И причину я уже описал выше. А далее я делаю вывод, что вы используете это потому, что лайвтаймы — это введённые для компилятора кастыли. Вы итак видите продление времени жизни объекта — это вам не нужно. Именно поэтому вы и пытаетесь их писать write-only и после — игнорировать. Иначе подобное поведение не описать.

                Таким образом это что-то типа. let a; a = b; c = a; — т.е. у меня есть a', которое никак и ни к чему не привязано. Оно болтается в воздухе. Далее, оно неизвестно где и неизвестно как привязывается ко времени жизни одного и второго(и далее) объекта как-бы уравнивая время их жизни. И ты никак из этого 'a не узнаешь что это, зачем это и почему.

                Какой смысл в этом по сравнению с (a, b) -> c {return c{move(a)};} — я не вижу.

                Это совершенно разные сигнатуры функций. В Haskell идентификаторы используемые в сигнатуре функции и начинающиеся со строчной буквы обозначают именно любой тип.

                Я уже заранее ответил на это, но вы почему-то это проигнорировали. Никакие «любые типы» НИКОМУ и НИКОГДА не нужны. Это очень и очень редкий кейс.

                В C++ это будет template<a,b,c> c func(std::pair<a,b> val){...} и Iterator func(std::pair<Container, Value> val) — разные вещи, в общем.

                Это вещи идентичные. Либо вы не понимаете, что это шаблонные типы?

                template<Container, Value, Iterator> Iterator func(std::pair<Container, Value> val); А не то, что вы написали.

                Здесь у нас есть некий обобщённый(упрощённый) тип контейнера, который подразумевает контейнер, а не хрен пойми что. Некий обобщённый тип значения и некий обобщённый тип итератора. Т.е. имя наделяет переменную дополнительными свойствами, которых не на уровне языка. Но не только.

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

                Т.е. даже если у меня есть механизмы внутри самого языка ограничить множество типов в a только контейнерами, то мне проще использовать Container, а не смотреть что там и как определенно. Особенно если это тонна лапши. Это лишь дополнительная строгость уровня языка…

                Кстати, функция с сигнатурой (a,b) -> c довольно бессмысленна, так как может возвращать только bottom. Но это уже к обсуждению не относится.

                Что? В этом и проблема, что вы уже запутались. А если бы вы посмотрели на имена — вы бы сразу там увидели банальную сигнатуру find(a, b) -> c.


                1. mayorovp
                  17.10.2017 19:03

                  Нетривиальной функции template<Container, Value, Iterator> Iterator func(std::pair<Container, Value> val); которая бы делала что-то осмысленное в языке С++ существовать не может. Дальше думайте сами.


                  1. phponelove
                    17.10.2017 19:34
                    -2

                    Слив засчитан.

                    Нетривиальной функции template<Container, Value, Iterator> Iterator func(std::pair<Container, Value> val); которая бы делала что-то осмысленное в языке С++ существовать не может.

                    Что это за бредни? Во-первых откуда там взялся pair? Во-вторых — я уже назвал пример.

                    В любом случае — исход был заранее определён. Вы очень часто путаете ваши мечты и ваши возможности. Ваши возможности ограничены минусом «в крысу». В следующий раз не надо это путать. Остальные вон не перепутали.


                    1. mayorovp
                      17.10.2017 19:40

                      Вообще-то это была цитата из вашего же комментария. Слив засчитан :-)


                  1. 0xd34df00d
                    17.10.2017 19:53

                    Разница между хаскелем и плюсами в том, что плюсы тайпчекаются после мономорфизации, поэтому технически может.

                    Вы можете написать тело этой функции так (с точностью до неопределимости компилятором Iterator, но это к делу не очень относится, вероятно), будто вам передадут пару только из, скажем, вектора строк и строки. Если эту функцию действительно вызовут в таком контексте, то всё будет хорошо.

                    Более того, вы можете считать, что вам передадут, скажем, вектор объектов с определённым оператором сравнения и объект того же типа (и тогда её даже имеет смысл делать темплейтом), и пока функцию будут вызывать в этом контексте, тоже всё будет хорошо.

                    Иными словами, совсем коротко:

                    template<typename T>
                    int f(T t)
                    {
                        return t;
                    }
                    
                    int main()
                    {
                        return f(0);
                    }
                    


                    1. mayorovp
                      17.10.2017 19:54

                      Я не случайно написал что функция должна делать что-то осмысленное.


                      1. 0xd34df00d
                        17.10.2017 19:59

                        В вашем случае она вполне может искать второй элемент пары в первом, например.


                        1. mayorovp
                          17.10.2017 20:11

                          Независимо от того что она делает на самом деле, Iterator следует убрать из параметров шаблона и заменить на Container::iterator


    1. ozkriff Автор
      17.10.2017 09:31
      +3

      Вот хороший пример читаемости синтаксисов

      кстати, по этой логике победителем должен быть питон, почему его (или еще какой скриптоты) даже в списке нет :(?


      def typeList(arch, offset, parseDecl):


      (это я тонко намекаю на потерю информации)


  1. helgihabr
    17.10.2017 10:12

    >> То есть 5 будет положено в стек или возможно в регистры, а x будет ссылкой на него
    Можно ли точно знать куда будет положено значение (в стек или же в регистр) или здесь нет четкого правила?


    1. mayorovp
      17.10.2017 10:21
      +2

      Зависит от того, сможет ли оптимизатор кода заинлайнить его до такой степени что ссылка станет не нужна. Если сможет — то значение будет кандидатом на передачу через регистр, если вообще останется после всех оптимизаций. Если не сможет — то конечно же оно попадет в стек, потому что на регистр ссылку передать нельзя.


    1. ozkriff Автор
      17.10.2017 13:18
      +1

      На уровне языка, насколько я знаю — нельзя.


      Но если очень надо, можно, как и в других системных языках, для конкретного приложения на конкретной архитектуре дизасм посмотреть и попытаться подогнать код так, что бы оптимизатор затолкал что нам там надо в регистр. Только с этим, конечно, надо быть осторожным и много раз перепроверить что в итоге вышла реально оптимизация — а то LLVM умный, его не так-то легко перехитрить руками обычно.