Rust: Аргументы по умолчанию и аргументы ключевого слова

Созданный на 6 июн. 2013  ·  70Комментарии  ·  Источник: rust-lang/rust

Я не видел никаких проблем с аргументами ключевых слов, есть ли планы по этому поводу в будущем?


ПРИМЕЧАНИЕ. Система отслеживания ошибок - не место для обсуждения дизайна. Пожалуйста, направляйте все обсуждения дизайна на etherpad ( https://pad.riseup.net/p/hvbg6dQQnEe7 ) или создайте страницу bikeshedding в вики.

Etherpads:

Самый полезный комментарий

Triage 05.08.2013: никакого прогресса (насколько я знаю), хотя все равно было бы аккуратно; может быть, синтаксис объявления может выглядеть как

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

где RHS - это любое постоянное выражение (т.е. вещи, которые допустимы в объявлении static ).

Все 70 Комментарий

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

fn foo(bar: int, qux=2: int, ham=0: uint) { ... }

Что затем может называться foo(1) , foo(1, 3) , foo(1, ham=4) , foo(6, 7, 8) и т. Д.

РЕДАКТИРОВАТЬ: см. Предлагаемый ниже синтаксис huonw, который выглядит намного лучше и более единообразным с текущим синтаксисом объявления.

Triage 05.08.2013: никакого прогресса (насколько я знаю), хотя все равно было бы аккуратно; может быть, синтаксис объявления может выглядеть как

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

где RHS - это любое постоянное выражение (т.е. вещи, которые допустимы в объявлении static ).

ИМО, они действительно полезны, даже система _default arguments_ С ++, где вы можете только вернуться к значениям по умолчанию для конечных неуказанных аргументов, была бы отличной ... сокращает количество альтернативных вариантов именованных функций, но при этом не так сложна, как перегрузка .. было бы здорово объявлять их в структурах и вариантах перечисления.
Возможно, это более простое подмножество требуемого поведения может быть реализовано до того, как будет достигнут консенсус относительно того, как / если вызывать параметры именованного ключевого слова ... это подготовило бы внутренние компоненты?

Было бы целесообразно / полезно реализовать в виде выражений ... с точки зрения ранее указанных аргументов и параметров универсального типа (например, возможность поиска нуля ::или напишите такие вещи, как slice (& self, start: uint , end: uint = self.len ()) / * "foobarbaz" .slice (6) == "baz" .. или create_window (parent, x, y, width : uint = parent.width () / 4, height: uint = (width_161) / 100) / _ default - это окна в форме золотого сечения и 1/4 ширины экрана, если вы не укажете размер вообще .. * / .. .. или это просто похоже на рецепт раздутого кода ..

Значения по умолчанию в стиле c ++ исключают частичное функциональное приложение, подобное haskell, но я слышал, что это вряд ли войдет?

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

Итак, учитывая прекрасный пример @huonw :

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

... мы могли бы вызвать это как foo(1, 2, None) , foo(1, _, Some(1)) , foo(1, _, _) и т. д.

Однако эта идея на самом деле не принесет никаких преимуществ для принятия аргументов ключевого слова, учитывая, что она все еще строго позиционна.

Изменение заголовка на «Аргументы по умолчанию и аргументы ключевого слова».

не реализовано, но я попытался добавить в ast & parser; https://github.com/dobkeratops/rust/compare/default_args , это правильный способ сделать это? (Вариант @expr .. потребуется ограничение на то, что может быть expr?)
опуская пальцы ног в воду, чтобы поэкспериментировать с этой функцией.
Я был бы заинтересован в том, чтобы увеличить подмножество C ++ api, которое можно было бы перевести, и это определенно то, чего мне не хватает в C ++, и функция named keyword была бы потрясающей по сравнению с тем, что делает C ++.
Казалось, что использовать второй предложенный синтаксис объявления просто и логично.

@dobkeratops, который выглядит хорошо (хотя type Default = Option<@expr> , вероятно, не нужен).

Ограничения на expr переходят в rustc::middle::check_const ; вам нужно будет добавить такую ​​функцию, как check_fn которая проверяет каждый аргумент. (Кроме того, по-видимому, должна быть проверка, что аргументы по умолчанию появляются только в конце; и я думаю, что должно быть что-то в средстве проверки типов rustc::middle::typeck , а также в trans . )

Хорошо, поле названо так, что это не случайная аннотация.
Спасибо за указатели, где искать, я искал в rustc :: middle :: typeck :: .. mod.rs (check_fn something).

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

Это только разрушительно, если вы определенно решитесь против них?

Кто-то предположил, что подобные вещи можно использовать с параметром -Z (..Session :: debug_opts ... но я не обнаружил, что в настоящее время они распространяются повсюду (например, в парсере).

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

@dobkeratops Обратите внимание, что ни один официальный разработчик еще не прокомментировал это, поэтому очень маловероятно, что какой-либо PR будет принят. Здесь необходимо провести много дискуссий относительно: 1) хотим ли мы аргументов по умолчанию, 2) если да, то каким должен быть синтаксис и 3) хотим ли мы аргументов ключевого слова (потому что семантика, которую мы выбираем для аргументов по умолчанию, может препятствовать этому. ).

Хорошо, я предполагаю, что они будут иметь очень низкий приоритет еще долгое время, поскольку они ничего не блокируют (они, конечно, не являются главными в моем собственном списке желаний).
Просто подумал, что это может быть низко висящий плод и еще одно знакомство для C ++ людей ...
Я полагаю, что макросы иногда могут выполнять аналогичную работу (и даже больше) ... и я могу лучше научиться именовать общие / необычные варианты

Я вижу, что именованные аргументы не критичны, но не обязательные аргументы IMO. Потому что в некоторых местах, мне кажется, я видел несколько методов с похожими сигнатурами и похожими именами, чтобы предложить более простые интерфейсы, когда данный аргумент не нужен. Было бы отстой, если бы мы остались такими устаревшими функциями только потому, что какая-то функция отсутствовала.

Здесь много тонких деталей. Все аргументы по умолчанию являются неявной формой перегрузки, поэтому (я предполагаю), вероятно, будут интегрированы с алгоритмом разрешения признаков и / или выводом типа. Это может быть не очень сложно, но это стоит тщательного проектирования, и на данный момент я не уверен, что у нас есть на это время. Я полагаю, что это функция _language_, обратно совместимая; в качестве функции api она, вероятно, проинформирует некоторые аспекты дизайна api, поэтому представляет собой риск bc.

@Seldaek Я согласен с тем, что если нам нужны аргументы по умолчанию, важно реализовать их, прежде чем мы сделаем обратную совместимость с stdlib. Однако я знаю по крайней мере один язык (Go), который философски отвергает аргументы по умолчанию в пользу подхода «функции с немного другими именами и сигнатурами».

Однако, в отличие от Rust, Go имеет несколько функций, которые делают отсутствие аргументов по умолчанию менее болезненным. Во-первых, у них есть вариативные функции. [1] Во-вторых, вам разрешено опускать поля при создании структур, что означает, что легко передать структуру конфигурации функции (пропущенные поля, по-видимому, имеют значения по умолчанию, указанные компилятором (?), А не то, что пользователь может настроить). [2]

Что касается первого, мы могли бы обойтись без макросъемки для достижения того же результата (хотя и с трудоемкими затратами на реализацию). Действительно, предстоящая замена для fmt!() делает следующее:

ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3)

Это код, который работает сегодня.

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

struct Foo { x: int, y: int, z: int }

impl Foo {
    fn default() -> Foo {
        Foo{x: 0, y: 0, z: 0}
    }
}

fn bar(f: Foo) {
    printf!(f);
}

fn main() {
    bar(Foo{y: 5, ..Foo::default()});
}

В прошлом я видел, как этот метод небрежно предлагался в качестве обходного пути из-за отсутствия аргументов по умолчанию, но на практике он довольно неудобен (сравните bar(Foo{y: 5, ..Foo::default()}) с bar(y=5) или мое более консервативное предложение bar(_, 5, _) ), и, конечно, он заставляет всех вызывающих создавать структуру, даже если они _do_ хотят передать все аргументы.

Повторюсь, как человек, пришедший из Python и Javascript, я, очевидно, приветствовал бы аргументы по умолчанию. Тем не менее, я несколько сочувствую философии Go, заключающейся в том, чтобы сделать API явными (в обмен на (потенциально значительно) завышение количества функций в самом API).

[1] https://groups.google.com/d/msg/golang-nuts/NWMReL1HueQ/X9mdYduCOB8J

[2] http://stackoverflow.com/questions/2032149/optional-parameters

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

@bstrie спасибо за обзор Go. Я согласен с тем, что перегрузка, вероятно, плохая идея, потому что она создает запутанные API. Точно так же «перегруженные» методы jQuery, которые могут выполнять обратный вызов практически для любого аргумента, который вы хотите, очень странны и трудны для реализации.

И я вроде как согласен с тем, что функции-оболочки для заполнения аргументов по умолчанию в некоторых случаях не так уж и плохи. Но проблема в том, что, хотя он избавляет вас от некоторых запутанных случаев, он вводит много шаблонов в других. Один из примеров - *::to_str_radix(num, radix) . Если бы у нас были необязательные аргументы, их можно было бы сложить в *::to_str(num, radix = 10) . Я чувствую, что в некоторых случаях стремительный рост вариантов функций действительно делает вещи менее интуитивными и трудными для запоминания. Конечно, всего лишь два цента.

Я вижу, что это хороший компромисс, чтобы отложить их;
но действительно ли они игнорируют значения по умолчанию с философской точки зрения, или это просто оправдание сделанных ими компромиссов в отношении бюджета времени при реализации? Я был бы удивлен, если бы кто-нибудь подумал, что пробираться через long_function_names_with_lots_of_trailing_qualifiers - это шаг вперед :), но если бы они сказали, что «это позволяет нам использовать простые инструменты, мы еще не разработали мощную среду IDE…» это другое дело.

Я определенно скучаю по перегрузкам и значениям по умолчанию из C ++ ... но я был счастлив обменять их на другие удобства Rusts и обещание альтернативы C ++ (после того, как я так долго застрял на одном основном языке ...)

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

Одна вещь, к которой я все еще действительно привыкаю, - это то, что теоретически методы гораздо более применимы в ржавчине.
Вернувшись в C ++, я боюсь их из-за проблем с заголовком / зависимостью (это основная причина, по которой я здесь), поэтому я часто инстинктивно сначала использую функции.
Возможно, я буду меньше скучать по умолчанию, когда буду лучше использовать ржавчину.

Просто чтобы идея не исчезла: болтливый аспект bar(Foo{y: 5, ..Foo::default()}) мне кажется частью ..Foo::default() .

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

Например, новая форма, которая, вероятно, определена исключительно для структур, реализующих какую-либо соответствующую черту ( Zero или Default или что-то еще), которая выглядела так:

Foo{y: 5, *) где * заменяет предыдущее ..Foo::default() .

Тогда пример "просто" bar(Foo{y: 5, *}) . Возможно, другие предпочли бы, чтобы Foo тоже не было, но мне это кажется довольно чистым.

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

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

html::start_server(html::ServerOpts{port: 10088, *});

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

Фактически, если использовать мой собственный пример, при инициализации чего-то с большим количеством параметров, таких как HTML-сервер, я, вероятно, был бы так же счастлив, предварительно настроив структуру server_opts а затем просто вызвав start_server(server_opts) . И я действительно не против добавить строку с ..html::ServerOpts::default если инициализация моей структуры уже охватывает несколько строк.

Я думаю, что, возможно, нам нужно переосмыслить, где аргументы по умолчанию были бы наиболее полезными. На мой взгляд, здесь не так много потенциальных аргументов; они должны быть довольно редкими, и несколько строк для инициализации структуры конфигурации вполне подойдут. Скорее, я чаще всего пропускаю аргументы по умолчанию, когда 1) операция довольно распространена и 2) операция имеет не более одного или двух аргументов, которые почти всегда являются лишними, но необходимы для полноты. Например:

let foo = Some('a');
foo.unwrap();  // same as today
foo.unwrap('z');  // imagine that this replaced unwrap_or_default

int::from_str("4");  // same as today
int::from_str("4", 16);  // imagine that this replaced from_str_radix

Однако теперь, когда я напечатал их, я действительно предпочитаю явность отдельных методов. :) Может, я все-таки не знаю, чего хочу!

@dobkeratops ,

Комментарии в https://github.com/mozilla/rust/wiki/Meeting-weekly-2013-08-13, похоже, указывают на то, что разработчики видят в этом особенность далекого будущего. Выдвижение.

Я считаю, что OCaml делает необязательный аргумент / аргумент по умолчанию без перегрузки. Необязательные аргументы типа T без значения по умолчанию неявно преобразуются в параметр T, и функция должна проверять, было ли предоставлено значение. Также существуют ограничения на объявление и использование необязательных аргументов, чтобы компилятор знал, когда аргумент был опущен. Все необязательные аргументы должны иметь метки (они должны быть ключевыми аргументами, чтобы быть необязательными). Это усложняет систему типов OCaml (метки становятся частью типа функции), но я думаю, что это артефакт необходимости взаимодействия с остальной системой типов Хиндли-Милнера.

Исходя из C ++, мне бы очень не хватало значений аргументов по умолчанию. Я часто использую функции с большим количеством параметров, где большинство из них почти всегда имеют значения по умолчанию, за исключением некоторых редких случаев использования или тестовых случаев. Добавление чисто комбинаторных производных имен функций вместо значений по умолчанию создало бы большой беспорядок из действительно длинных имен.

Я согласен с тем, что аргументы по умолчанию и / или аргументы ключевого слова были бы чрезвычайно полезны. Я думаю, мы должны работать над предложением до версии 1.0, в котором излагается, что необходимо сделать с точки зрения перегрузки, и, возможно, обсудить синтаксис.

Приятно видеть, что все больше людей высказываются за :) Еще одна причина, по которой я хотел, это увеличение количества API C ++, которые можно было бы легко переводить. Использование библиотек C ++ - одна из основных причин, по которой мы застряли на C ++.

Я подозреваю, что единственный способ получить это, если бы сообщество могло _ реализовать это_ без каких-либо затрат для основных разработчиков.
Я согласен, что у них есть гораздо более важные дела, и перечисления восстанавливают утраченный полиморфизм с возможностями, не сразу очевидными для мозга, обусловленного C ++.

Вот почему я хотел представить наработки по синтаксическому анализу в структуре данных AST. Он был бы готов, чтобы кто-то другой поднял его и попытался найти решение. первоначальная обратная связь отговорила меня от пиара.

из c ++ Я с завистью смотрю, что есть в scala и python. Родной язык без сборщика мусора с такой элегантностью был бы великолепен.
..его больше функций в одном месте, меньше навигации, чтобы понять, что происходит, меньше глубины вложенности, меньше шума в исходном коде. Не только банально меньше набора текста.
возможно, вы могли бы даже заявить, что он более самодокументирован, сигнатура функции расскажет вам больше о том, как его использовать.

труднее всего является проверка типов, предотвращающая малозаметные ошибки и сбивающие с толку ошибки, если бы это было сделано просто как взлом парсера.

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

fn substr(a:&str, start:int, end:int=a.len())->~str

просто взломайте такие вещи в AST без проверки ошибок, я уверен, что многое может пойти не так ... но представьте, если бы мы могли исправить это, чтобы сделать то, что ожидалось :)

Просто ошибка. Мы можем обсудить достоинства, но не будем блокировать выпуск по этому поводу.

Мне нравится поведение, которое @tautologico описывает в своем комментарии.

Применительно к Rust я считаю, что это привело бы к следующему:

fn ga(bu: int, zo: Option<int>, meu: Option<int>) {
  let zo = zo.get_or_default(42);
  let meu = meu.get_or_default(99);
  ...
}

И все это будут действительные вызовы:

ga(10, 20, 30); // 20 and 30 are automagically
                // converted to Some(20) and Some(30)
ga(10, 20);         // ga(10, 20, 99) 
ga(10);             // ga(10, 42, 99)
ga(10, None, None); // ga(10, 42, 99)
ga(10, 20, None);   // ga(10, 20, 99)
ga(10, None, 30);   // ga(10, 42, 30)

Правило состоит в том, что завершающие параметры Option<T> могут быть опущены. Здесь повторно используется тип Option , но если это вызовет некоторые проблемы, может быть создан другой, более конкретный тип OptParam .

Это предложение позволяет вызывающему абоненту точно выбрать параметры, которые он хочет предоставить, и те, которые он хочет сохранить по умолчанию, независимо от своего положения. Кроме того, я думаю, что это хорошо, что значение по умолчанию не отображается в списке параметров. Таким образом, значение по умолчанию не ограничивается константным выражением, оно может зависеть от состояния объекта или от других параметров.

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

fn showDialog(message: ~str,
              parent: Option<Widget>,
              title: Option<~str>,
              type: Option<DialogType>,
              icon: Option<Icon>) { ... }

// Display an info box in the middle of the screen.
// Set the title to "information", translated in the current locale
// Set the icon to an "info" icon
showDialog(~"hello, world!");

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a "warning" icon
showDialog(~"sick, sad world!", None, None, WarningDialog);

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a custom icon
showDialog(~"sick, sad world!", None, None, WarningDialog, bugIcon);

В этом примере:

  • значение по умолчанию parent - None (без родителя)
  • значение по умолчанию type - InfoDialog
  • значение по умолчанию icon зависит от значения type
  • значение по умолчанию title зависит от значения type и текущей локали

Теперь вы также предлагаете добавить Option в качестве нового примитивного типа. Сейчас это полностью библиотечная функция, так как это старый добрый enum .

Я хотел бы добавить, что аргументы IMO по умолчанию в миллиард раз лучше с аргументами ключевого слова. Мне не нравится идея аргументов по умолчанию, но нет аргументов ключевого слова.

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

Значения по умолчанию для позиционных аргументов приводят к загадочному коду. Почему не используются только значения по умолчанию для аргументов ключевого слова? (Если они реализованы).

ИМО ... это не "или-или".
Они оба полезны. Один проще реализовать, с меньшим выбором синтаксиса;
так что для нас имеет смысл сделать это или попытаться реализовать это в первую очередь, как ступеньку ...

Почему пропуск значений по умолчанию более загадочен, чем обычные вызовы функций? Программисты на C ++ уже привыкли сортировать параметры по этим параметрам. Обычно какое-то слово контрольных флагов с разумным значением по умолчанию в конце ... просто опускайте значение вместо того, чтобы писать (.., BLAH_DEFAULT) что бы то ни было ... поясняет, перечисляя только важную информацию. Люди, которым нужен Rust, скорее всего, уже имели дело с C ++ и, следовательно, привыкли к нему.

Ранее сегодня я понял, что в моем предложении выше (который пытался использовать существующий синтаксис расширения структуры, чтобы предоставить что-то близкое к аргументам по умолчанию, поскольку я рассматриваю структуры как уже предоставляющие ингредиенты для аргументов ключевого слова) игнорирует одну важную проблему: синтаксис, который я предлагал предполагается, что можно указать значение по умолчанию для _every_ аргумента (а затем все они будут перенесены в один параметр структуры).

Это, конечно, не так в целом: довольно часто одни аргументы являются обязательными, а другие - необязательными.

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


Мой текущий мозговой штурм был сосредоточен на том, можем ли мы использовать существующий синтаксис структуры, возможно, путем добавления выражений по умолчанию для полей в определении элемента структуры. Это позволило бы иметь некоторые поля, которые можно было бы отбросить, и другие, которые потребуются. Что-то типа:

struct Foo { x: int = 0, y:int = 0, z:int = 0 }

fn bar(f: Foo) {
    printf!(f);
}

struct Baz { x: int, y: int, z:int = 0 }

fn quux(g: Baz} {
    printf!(g);
}

fn main() {
    bar(Foo{y: 5});
    quux(Baz{y: 5}); // ~ERROR: required field, `x`
}

@pnkfelix Мне нравится это предложение, может быть, было бы не так уж сложно использовать те же внутренние

fn bar({ x: int = 0, y:int = 0, z:int = 0 }) {
    printf!(f);
}

fn quux({ x: int, y: int, z:int = 0 }) {
    printf!(g);
}

fn main() {
    bar({ y: 5 });
    quux({ y: 5 }); // ~ERROR: required field, `x`
}

@visionmedia @bstrie Нам действительно нужно объявление использования повторной привязки не решает проблему длинных имен,

То есть, с примером ServerOpts, который мне посоветовал bstrie:

fn main() {
  use O = html::StartServerOptions;
  ...
  html::start_server(O{port: 10088});
}

@pnkfelix мне нравится

struct Foo {
   x: int = 10,
   y: float = 1.0
}

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

struct FooOptions { ... }
static default: FooOptions = FooOptions { ... };
fn foo(compulsory: int, required: uint, necessary: float, optionals: FooOptions) { ... }

FWIW, мне также нравится идея структуры со значениями по умолчанию. Думаю, это был бы ярлык для:

struct Test {
    m: int,
    y: int
}

static DEFAULT: Test = Test{m: 10, y: 15};

Test{y: 5, ..DEFAULT}

Мне также нравятся значения по умолчанию внутри определения.

У меня тоже есть синтаксический анализ с этим синтаксисом, но на самом деле он не использовался ... Я все еще не знаю, как обойти исходный код проверки типов и т. Д.

Возможно, тот факт, что там уже есть механизм по умолчанию, может немного облегчить его реализацию.

ре. анонимные структуры, я думаю, они у них изначально были, но пришлось удалить их «из-за странных взаимодействий»?
я бы предпочел, чтобы были доступны оба механизма. возможно, структуры параметров устранят необходимость в аргументах _keyword_, но конечные значения по умолчанию, такие как в C ++, по-прежнему будут удобны

для справки -
http://www.parashift.com/c++-faq-lite/ named-parameter-idiom.html
lol - интересные, но верные аргументы ключевого слова позволили бы избежать необходимости в шаблонных тяжелых хаках, подобных этому

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

Изначально все типы структур были структурными. Я считаю, что они были удалены (заменены номинальными типами структур) из-за неудобного взаимодействия с чертами.

Мне нравятся значения по умолчанию в идее определения структур. Это кажется легким для понимания и, по крайней мере, позволяет избежать необходимости перечислять каждое поле при построении структуры - это проблема для структур типа «параметры», потому что это означает, что при добавлении нового «необязательного» поля каждый сайт вызова должен быть изменен на инициализировать его значением 0 / None / и т. д.

Исходя из Perl (где значения по умолчанию являются специальным шаблоном), Python 2 (где вы можете получить foo() takes at least 2 arguments (2 given) ) и Python 3 (где вы можете иметь только именованные аргументы _ без_ значений по умолчанию), я скромно предлагаю: добавить _teeny_ бит сахара, позволяющий объявить структуру в качестве последнего аргумента функции, но разрешить вызывающей стороне _inline_ поля структуры.

например

impl int {
    struct FromStrOptions {
        radix: uint = 10
    }
    fn from_str(s: str, opts: FromStrOptions) -> int {
        // ...
    }
}

int::from_str("4", radix: 10);

Преимущества:

  • Нет нового синтаксиса для определения функции, которому на самом деле совершенно не нужно заботиться о том, как вызывающий его вызывает. Это похоже на то, как работает передача блоков с помощью do : это исключительно забота вызывающего абонента. (Должен ли быть способ выбрать / отказаться, в случае наличия последнего аргумента, который является структурой, но не предполагает, что он будет использоваться для kwargs? Кому-нибудь будет интересно? Я не думаю, что кто-то заботится о do .)
  • Двоичный макет, семантика вызовов C и т. Д. Все еще довольно четко определены.
  • Когда-нибудь перегрузку по типу или арности реализовать не составит труда, за исключением того, что тип последнего аргумента не может способствовать перегрузке типа. Также не должно мешать вариативным аргументам, если это когда-либо произойдет.
  • Одинаковый набор значений по умолчанию можно повторно использовать в нескольких функциях.
  • Что-то вроде **kwargs бесплатно: просто создайте структуру и передайте ее как позиционный аргумент.
  • Обязательные аргументы ключевого слова выпадают из этого естественным образом: просто не указывайте значение по умолчанию в структуре, и вы вынуждены передавать _something_ по имени.
  • Никакой дурацкой путаницы при передаче позиционных аргументов по имени; ты просто не можешь этого сделать.

Недостатки:

  • Немного волшебно. Но я думаю, не более чем передача 5 и вывод типа из argspec функции.
  • Непонятно, как это будет взаимодействовать с существующей идиомой do . Может быть достаточно просто сказать, что это должен быть последний аргумент _written_, т.е. он работает как предпоследний аргумент только при использовании с do .

FWIW int::from_str("4", radix: 10) будет конфликтовать с ранее предложенным использованием : качестве оператора приписывания типа.

Проклятия, предотвращенные ASCII.

int::from_str("4", radix☃ 10)

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

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

Мы говорили об этом вчера вечером на еженедельном

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

Команда также решила, что решение этой проблемы каким-либо образом не является приоритетом для версии 1.0. Руководитель проекта

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

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

Позвольте мне уточнить.

Аргументы функции по умолчанию _критичны_ для хорошего дизайна API; их отсутствие усложняет использование более простых API. Примеры из библиотеки std:

  • concat и connect вместо просто concat которое может использовать разделитель.
  • split_iter и splitn_iter более split_iter с необязательным count . То же самое с rsplit_iter и rsplitn_iter .

И другие.

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

Если аргументы по умолчанию откладываются на срок после 1.0, то эти функции в библиотеке std нельзя удалить из-за обратной совместимости. Это означает, что даже если в будущем будут добавлены аргументы по умолчанию и «ванильная» версия функций теперь сможет выполнять работу других вариантов, старые варианты останутся неизменными, и разработчики должны будут знать о них, потому что кто-то обязательно будет использовать их, пусть даже по ошибке.

Так что дополнительная когнитивная нагрузка останется _ навсегда_.

[NB. Тот же аргумент можно привести для перегрузки функции на основе типа параметра (текущий обходной путь на основе характеристик слишком громоздок, и функции библиотеки std не используют его), но этот вопрос не место для такого обсуждения.]

Разработчики Rust, спасибо за то, что поработали над Rust и сделали его потрясающим!

Я добавляю веху «далекого будущего», чтобы подчеркнуть крайнее разочарование, которое мы в основной команде хотим донести до любого, кто потратит секунду времени на эту проблему. Если вы хотите внести свой вклад в Rust прямо сейчас, пожалуйста, устраните одну из 41 открытой ошибки на этапе 1 (четкость):

https://github.com/mozilla/rust/issues?milestone=12&state=open

или одна из 104 открытых ошибок на этапе 2 (обратная совместимость):

https://github.com/mozilla/rust/issues?milestone=13&state=open

или одна из 68 открытых ошибок на этапе 3 (функции, которые мы согласовали в какой-то момент, имеют решающее значение для выпуска Rust 1.0):

https://github.com/mozilla/rust/issues?milestone=14&state=open

или даже просто прокомментируйте одну из этих ошибок, чтобы попросить разъяснений или предложить способы достижения прогресса. Это 213 ошибок на выбор; достижение прогресса по любому из них на данном этапе было бы гораздо более ценным для Rust, чем эта проблема. И всем, кто сможет закрыть одну из этих ошибок, мы будем очень благодарны.

Я вижу, что у основной команды есть гораздо более важные дела, но мне кажется позором «выражать крайнее разочарование» :(
+1 к комментариям к валлорикам. именовать сложно, копаться в документации и узнавать больше имен - это неприятно ...; аргументы / overloard по умолчанию упрощают задачу; с ключевым словом args у вас будет возможность выйти за рамки C ++ в этом вопросе. (Я бы хотел, чтобы у github было голосование, я мог бы просто нажать +1 вместо того, чтобы разглагольствовать здесь, лол)

@Valloric Я полностью согласен (как я уже говорил ранее) и очень надеюсь, что команда ядра ржавчины пересмотрит или, по крайней мере, повторно обсудит необязательные аргументы, потому что это влияет на дизайн API. Именованные аргументы определенно могут подождать, поскольку они в основном влияют на сайт вызова (конечно, имя аргументов становится частью дизайна API после того, как мы назвали аргументы, поэтому оно оказывает небольшое влияние, но не разрушает BC, если имена аргументов очищаются при введении именованных аргументов).

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

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

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

Я не говорю, что другие языковые функции, которые необходимо исправить / реализовать, не являются более важными; они, вероятно, есть. Но это не то или другое. Все, что я говорю, это то, что эту функцию следует строго рассмотреть для версии 1.0 (в дополнение к другим функциям), потому что ее отсутствие влияет на качество API в библиотеке std _forever_.

Это, вероятно, спорное мнение, но языки программирования IMO живут и умирают больше из-за API, которые они предоставляют, чем из-за их основных функций. Стандартная библиотека Python "с батарейками" продала весь язык. CPAN поддерживает Perl. .Net делает написание кода C # потрясающим, а LINQ - это лучшее, что есть после нарезанного хлеба. Один из самых больших недостатков C ++ - отсутствие хороших стандартизованных API. И Т. Д.

API-интерфейсы критически важны для успеха языка, поэтому функции, позволяющие создавать _good_ API-интерфейсы, не следует отбрасывать как «несущественный синтаксический сахар».

@dobkeratops : говоря _dreaming up_, я пытаюсь подчеркнуть, что не было сделано полного предложения, поэтому оно не находится на этапе принятия решения

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

Если кто-то предлагает предложение, в котором проработаны почти все детали (грамматика, семантика), я предлагаю отправить его в список рассылки. Если достигнут консенсус в отношении того, что это _правильный путь_, то имеет смысл открыть проблему и реализовать ее в качестве экспериментальной функции за флагом вроде once functions.

Второй @thestinger - если у кого-то (или небольшой группы людей) есть полное предложение или предложение с несколькими четко прописанными пустыми пятнами, которые подлежат обсуждению, было бы уместно, чтобы этот человек запустил его. по списку рассылки. Это не обещание, что мы реализуем это предложение, но выполнение работы по формализации идеи и объяснению того, как она взаимодействует с другими языковыми функциями, значительно повысит ценность предложения.

@thestinger @catamorphism Спасибо вам обоим за

Я создал блокнот, чтобы обсудить эту функцию и написать о ней четкую спецификацию: https://pad.riseup.net/p/hvbg6dQQnEe7

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

@brson Спасибо!

Я отредактировал исходный выпуск со ссылкой на etherpad.

Привет.
С момента создания колодки возникло множество дизайнерских предложений, вопросов, проблем и т. Д.
Итак, я создал вторую панель, чтобы «резюмировать» панель обсуждения, эта панель будет использоваться для точного описания запроса функции.
URL-адрес панели здесь: https://pad.riseup.net/p/Ca5PBeDjUGxW

@KokaKiwi, все

@cmr , я думаю:

ВНИМАНИЕ: эта панель будет УДАЛЕНА, если прошло 30 дней без изменений. После этого НЕЛЬЗЯ восстановить подушку, поэтому будьте осторожны!

: frowning:

Я на самом деле ищу планшет, который я создал на экземпляре Mozilla Etherpad (чтобы предотвратить этот случай), но я не могу найти его в своей истории, и я забыл опубликовать ссылку здесь :(

@cmr @huonw @KokaKiwi , вот две ссылки в моей истории браузера:

https://etherpad.mozilla.org/CQEDa85jLX
https://etherpad.mozilla.org/78FA1bozLd

@dram Вот что я искал! Спасибо: smiley:
Думаю, вопрос стоит отредактировать с новыми ссылками.

(Отредактировано.)

Мне нечего добавить, кроме того, что я внимательно наблюдаю за этим, прежде чем уделять больше времени языку. Исходя из языков (Objective-C и Python), в которых есть эта функция, я считаю, что именованные параметры косвенно существенно повышают производительность, поскольку они заставляют код других людей быть более читабельным.

Конкретное предложение должно быть сделано через новый процесс RFC: https://github.com/rust-lang/rfcs

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги