Comments 98
Ну и есть всякие другие фичи, но они скорее направленны на максимально эффективную компиляцию, вроде уникальных типов у разных лямбд. Это уже трейдофы и однозначным минусом это назвать нельзя. Но если это можно победить и код работающий я парой-тройкой замыканий перестанет выглядеть инопланетной дичью, то я только за.
максимально эффективную компиляцию, вроде уникальных типов у разных лямбд.
А как это относится к эффективной компиляции? Лямбды в Расте имеют разные типы по той же причине, что и в С++. Лямбда — это просто синтаксический сахар для анонимной структуры с соответствующим методом. Две лямбды — две разные структуры, соответственно тип у них разный.
Какую реализацию вы предлагаете как более удобную? С учетом того что язык компилируемый, нативный и с минимальным рантаймом.
А как это относится к эффективной компиляции? Лямбды в Расте имеют разные типы по той же причине, что и в С++. Лямбда — это просто синтаксический сахар для анонимной структуры с соответствующим методом. Две лямбды — две разные структуры, соответственно тип у них разный.
Ну можно было бы боксить по-дефолту и проводить эскейп анализ. Да, звучит сложно, но зато при необходимости связать пару функциональных параметров не пришлось бы городить монстров вроде такого: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=3c0bec29d4f38f8eedae7a42446f0480
Для сравнения. вот так этот же код выглядит на скале:
def stateMonad[S]: Monad[State[S, ?]] = {
type StateS[A] = State[S, A]
new Monad[StateS] {
override def mreturn[A](a: => A): StateS[A] = State(s => (a, s))
override def bind[A, B](f: StateS[A])(g: A => StateS[B]): StateS[B] =
State[S, B](
s1 => {
val (a, s2) = f.run(s1)
g(a).run(s2)
}
)
}
}
Просто очередное изнасилование журналиста ученым (как всегда, ради громкого заголовка):
Hi Ryan Levick here. Microsoft is not moving away from Rust. Verona is a research project to explore different memory safety models for systems programming. Verona is in part inspired by Rust (as well as pony and C#). It is not a fork of Rust or meant as a Rust replacement. It’s very early days in Verona’s development and hard to say what it’s future will be. The hope is to learn from Rust and if possible contribute back learnings into the language. This isn’t a zero sum game. The talk linked to in the CDNet article should hopefully clarify things. That article was very misleading.
Репозиторий проекта уже опубликован на Github.
Кхм. Но там ничего нет кроме файла лицензии.
Сначала был Rust, который умел исключать ошибки при работе с памятью, но в это время группа сотрудников Microsoft обнаружила в Rust фатальный недостаток — его писали не они! Они немедленно исправили этот недочет, создав Verona, который как Rust, но другой.
По иронии судьбы, мем про "фатальный недостаток" обязан своим рождением Майкрософту
История программных революций от Microsoft
Как указывает ZDnet со ссылкой на Мэтта Миллера, специалиста Microsoft по безопасности, около 70% всех уязвимостей, которые были обнаружены в продуктах Microsoft в последние годы, были связаны с ошибками управления памятью.
Какой странный майрософт, все же знают что у настоящего программиста не бывает ошибок с памятью, особенно в программах написанных в последние годы. Вы покажите пару примеров кода, всем станет очевидно, что ни один программист в здравом уме такого не напишет.
〈/sarcasm〉
А в чем собственно проблема с <>
? Пример абсолютно нормальный, поэтому непонятно, что хотели им показать.
Если этот пример нормальный для раста (а не специально сделанное извращение), то это явно довод против него (с раст знаком шапочно, перевести не смог)
Ну вот так примерно будет выглядит в сишарпе:
class Reference<LifetimeA, Path> : PartialEq<Cow<LifetimeB, OsStr>> { ... }
Второй пример прямо не странслировать потому что в сишарпе нельзя условно наследовать интерфейсы только для части генерик аргументов. Примерно это может означать:
class Rc<TMaybeUninit> where TMaybeUninit : MaybeUninit<T>[] { ... }
Вся разница с шарповым кодом в том, что апострофы для лайфтаймов используются, да &
вместо Reference
. Вас так апострофы напугали?
Представленный синтаксис выглядит перегруженым и имхо менее дружелюбен к читателю чем синтаксис большинства популярных языков.
Я, как человек едва знакомый с албанским языком, ответственно заявляю, что понять там ничего невозможно.
Если не понимать, что такое лайфтаймы, трейты и т.п., то ничем не поможет и такая запись
declare lifetimes a, b
implement trait PartialEquality<CloneOnWrite(b)<OsCompatibleStringSlice>>
for reference(a)<Path>
impl<'a, 'b> PartialEq<Cow<'b, OsStr>> for &'a Path
не очень понятно)Это понятно если прочитать учебник по расту. На который емнип я потратил часов 6 чтобы прочитать от корки до корки.
Синтаксис учится один раз, а потом используется многократно. Поэтому вариант который взял раст на мой взгляд намного читаемее чем то что написано выше. Если в случае с
impl<'a, 'b> PartialEq<Cow<'b, OsStr>> for &'a Path
глаз сразу выцепляет "какие времена жизни, у кого, для кого", то в джава-стайл варианте выше глаз об стену текста разбивается
Вы обычно гуглите базовые понятия языка на котором ведете разработку? Вроде "что такое class" или "что значит null"?
Нет конечно. А к чему вопрос?
Этот вопрос адресован Clasen01
= вместо того, чтобы от этого ужаса избавиться, в Rust — почему-то решили скарго-культить это извращение. :(
![image](https://ic.pics.livejournal.com/nikpolmir/34583870/173695/173695_900.jpg)
Так предложите другой вариант. Просто я лично не вижу способа выразить это лучше, может я зашорен и не вижу очевидного варианта.
Просто большинство популярных языков не предоставляет ту информацию, которую предоставляет раст. Например, там обычно нет связи между временем жизни аргументов и результатом функции. В расте можно написать функцию, которую вернёт лямбду, по времени жизни привязанную к времени жизни аргументов. То есть
fn f(x: &i32) -> impl Fn() -> i32 + '_ {
move || *x
}
fn main() {
let y;
{
let x = 5;
y = f(&x);
println!("{}", y());
}
println!("{}", y());
}
С первым println всё хорошо, а вот со вторым — нет:
error[E0597]: `x` does not live long enough
--> src/main.rs:9:15
|
9 | y = f(&x);
| ^^ borrowed value does not live long enough
10 | println!("{}", y());
11 | }
| - `x` dropped here while still borrowed
12 | println!("{}", y());
| - borrow later used here
Поэтому сравнивать синтаксис с языками которые предоставляют меньше информации (например, в языке с ГЦ такое соответствие времен жизни указать нельзя, да и смысла там в этом мало) я считаю некорректно.
Ну да, конструкции типа
Arc<Mutex<Receiver<Option<Message<T>>>>>
Довольно многословны, но какие альтернативы? Разве что сделать какой-то разделитель одним символом, а не скобочками, типа
Arc!Mutex!Receiver!Option!Message!T
Но тогда как записывать, если типовых параметров больше одного? Какой синтаксис для лайфтаймов будет более удобен?
Довольно многословны, но какие альтернативы?
type Mailbox<T> = Arc<Mutex<Receiver<Option<Message<T>>>>>;
И теперь всего одна пара скобочек.
У меня единственное возражение против угловых скобок — это не скобки! Поэтому редакторы очень часто не могут подсветить соответствующую закрывающую/открывающую угловую скобку.
У квадратных скобок такой проблемы нет. Ну и визуально — хотя это вкусовщина, конечно — квадратные скобки чуть меньше сливаются с текстом.
type Mailbox[T] = Arc[Mutex[Receiver[Option[Message[T]]]]];
type Mailbox<T> = Arc<Mutex<Receiver<Option<Message<T>>>>>;
type Mailbox<T> = Arc.Mutex.Receiver.Option.Message<T>
Или так:
type Mailbox<T> = Arc*Mutex*Receiver*Option*Message<T>
Соглашусь, но так не видно вложенность. Нужна ли она — это другой вопрос.
Предлагаете отказаться от использования символа *
для указателя и операции разыменования? Что тогда вместо него?
В Rust можно так:
<MyType as FooTrait>::foo()
foo::<A, B>(a, b)
Поставите тут точку — и у вас развалится парсинг statements, потому что точка традиционно используется для обращения к полям и методам.
type Mailbox<T> = Arc^Mutex^Receiver^Option^Message<T>
type Mailbox<T> = Arc|Mutex|Receiver|Option|Message<T>
type Mailbox<T> = Arc+Mutex+Receiver+Option+Message<T>
type Mailbox<T> = Arc~Mutex~Receiver~Option~Message<T>
type Mailbox<T> = Arc Mutex Receiver Option Message<T>
type Mailbox<T> = Arc,Mutex,Receiver,Option,Message<T>
Я Раст не знаю, там что-то из этого свободно?
Последний вариант самый приятный и интуитивно понятный.
Почему у вас вдруг Option+Message<T>
? два синтаксиса для обозначения одного и того же. Тем более, что угловые скобки во всех популярных языках используются для генериков/шаблонов.
Странно жаловаться на инопланетный синтаксис раста и предлагать намного более экзотические варианты. тем более что все варианты кроме тильды дают неоднозначность парсинга, а тильды неудобно набирать и они плохо видны в коде. Да еще и не на всех клавиатурах есть.
В текущем виде грамматика раста практически контекстно-независима.
А как тогда записывать такое?
Rc<[MaybeUninit<T>]>
Или массивы и срезы уже не считаем за типы?
Я просто приводил пример, что квадратные скобки "выглядят лучше".
Разумеется, если квадратные скобки отдать под дженерики, то массивы и срезы надо записывать как-то иначе.
В Scala доступ к элементам массива делается через круглые скобки; подается это как перегруженный оператор() у типа массив. Определенная логика в этом есть, на мой взгляд.
Разумеется, менять синтаксис так кардинально в Rust уже поздновато.
Там NLL в этом году завезли, половину лайфтаймов можно не писать.
не бывает ошибок с памятью
Почитайте блог PVS Studio
Какой странный майрософт, все же знают что у настоящего программиста не бывает ошибок с памятью, особенно в программах написанных в последние годы. Вы покажите пару примеров кода, всем станет очевидно, что ни один программист в здравом уме такого не напишет.
〈/sarcasm〉
Это вобщем-то и без сарказма почти верно.
Просто "настоящие программисты" (в хорошем смысле) бизнесменам не нужны. Поэтому даже те, кто мог бы быть ими, обычно вынуждены играть роль плохих.
Код на Си транслируется в ассемблер практически без оверхеда. Более того, современные компиляторы часто могут сделать такие оптимизации, которые вручную было бы делать крайне муторно. А если ещё эти оптимизации зависят от платформы то всё ещё лучше в пользу Си. Те же места, где компилятору не повезло (их мало но они встречаются) можно сделать ассемблерными вставками, если там критична скорость.
А вот с управлением памятью ситуация совершенно другая. Автоматическое управление памятью всегда создаёт оверхед, и работает хуже чем это может сделать программист вручную. И вряд ли ситуация сильно изменится если только этим не займётся AI. Ну, насчёт оверхеда есть одно почти исключение — c++ управление временем жизни объектов (не указателей) при должном уровне компиляторных оптимизаций и при качественной реализации конструкторов копирования/перемещения, операторов присваивания (всё это с полноценным учётом const/nonconst аргументов) и деструкторов этих самых объектов, на современных компиляторах может быть с довольно маленьким оверхедом. Однако обычно это даже не считают автоматическим управлением памятью.
Вы то ли подменяете понятия то ли не понимаете сути. Я не знаю что и как в Rust, но ваши заявления касательно C/C++ странные.
Во-первых, "как C только контролируя безопасность" это и есть оверхед. В glibc например если поставить переменную окружения _MALLOC_CHECK=2 он тоже будет что-то контролировать, но это не продакшн функция а отладочная. Это если про само выделение/освобождение. Если же речь про невыход за границы выделенной памяти то это ещё больше оверхеда (при каждом обращении к массиву сверять индекс с чем-то в памяти, а уж как в таком режиме работать с type-casted указателями я вообще не знаю).
Во-вторых, когда я выше писал про c++ это было не про smart pointers а про RAII. Сам RAII добавляет немного (немного — повторюсь — на современных компиляторах и с качественной реализацией класса) оверхеда, а smart pointers с refcount — это абстракция над RAII которая добавляет ещё оверхеда. Если речь про без refcount то это тоже самое что статический объект. Случай с малым оверхедом это когда функционал smart pointer'а встроен в используемые классы, но не отдельной абстракцией а монолитно.
Иметь несколько указателей на объект это штатная фича указателей. А ещё бывают указатели на не-объект, например на позицию "+2 байта от начала переменной long long x;" (тип long long обычно 64-битный). То есть указатель это совсем-совсем не обязательно результат работы аллокатора для какого-то класса.
можно все это сделать через unsafe и сырые указатели.
То есть если хотим максимальной эффективности — возвращаемся в тому что было.
Во-первых, "как C только контролируя безопасность" это и есть оверхед. В glibc например если поставить переменную окружения _MALLOC_CHECK=2 он тоже будет что-то контролировать, но это не продакшн функция а отладочная. Это если про само выделение/освобождение. Если же речь про невыход за границы выделенной памяти то это ещё больше оверхеда (при каждом обращении к массиву сверять индекс с чем-то в памяти, а уж как в таком режиме работать с type-casted указателями я вообще не знаю).
Почти все проверки раст делает во время компиляции, и рантайм проверки можно тоже выключить. Например, компилятор раста автоматически проверит, что у вас ссылки не алиасятся, и на все указатели/ссылки в прогармме повесит __restrict. Надо ли говорить, что это не замедляет, а ускоряет программу?
Во-вторых, когда я выше писал про c++ это было не про smart pointers а про RAII. Сам RAII добавляет немного (немного — повторюсь — на современных компиляторах и с качественной реализацией класса) оверхеда, а smart pointers с refcount — это абстракция над RAII которая добавляет ещё оверхеда. Если речь про без refcount то это тоже самое что статический объект. Случай с малым оверхедом это когда функционал smart pointer'а встроен в используемые классы, но не отдельной абстракцией а монолитно.
Когда у вас язык построен вокруг владения, вы можете весь RAII сделать статически, и не тратить время в рантайме на рефкаунтинг.
То есть если хотим максимальной эффективности — возвращаемся в тому что было.
С указателями эффективность может быть даже ниже, см. тот же пункт про алиасинг.
Иметь несколько указателей на объект это штатная фича указателей. А ещё бывают указатели на не-объект, например на позицию "+2 байта от начала переменной long long x;" (тип long long обычно 64-битный). То есть указатель это совсем-совсем не обязательно результат работы аллокатора для какого-то класса.для таких случаев лучше иметь ссылку и смещение перенести поближе к использованию. А еще лучше вообще не складывать байты в целочисленные типы
Совместимость с C поддеживается, а нативный растовый ABI не слишком нужен в условияк сборки через cargo.
Но пока слишком велик риск допустить архитектурную ошибку. Я надеюсь, разработчики запилят GATы, а сейчас активно пилятся const-generics и другие фичи, и заморозить ABI значит обратить всё в legacy. Я лучше буду мучиться с перекомпиляцией пока.
Основным отличием Verona от Rust является применение модели владения на основе групп объектов, а не единичных объектов. Данные в Verona рассматриваются как структуры, представляющие собой коллекции объектов.
Для этого неплохо бы понять для начала, как выглядит эта модель владения "на основе групп объектов".
Мне кажется, тут ноги растут отсюда: http://joeduffyblog.com/2015/11/03/blogging-about-midori/
Но по мне так конкуренция — хорошо. Может кто-нибудь наконец то HKT реализует.
Не понимаю смысла городить новые языки.
Скажем, добавить новый синтаксис для взаимодействия с неуправляемым кодом и все такое.
Синтаксис C# действительно лаконичнее и читабельнее, но всё-таки zero-cost abstractions — это отдельная парадигма, под которую шарп изначально не затачивался, а если насильно натягивать язык на новую парадигму, мы получим ещё один C++ со всеми его проблемами.
Главный вопрос — а зачем?
Так синтаксис итак есть. И CoreRT для компиляции в нативный код разрабатывают. Но Майкрософт виднее
Хм, либо Windows достигла критической точки, когда тех долг уже настолько большой, что развивать систему становится настолько сложно, что проще переписать ее часть. Либо в Microsoft качество специалистов упало
Embrace, extend and extinguish
ЕГО ПИСАЛИ НЕ ОНИ! (,)
опять "давай сделаем такой же *, только лучше, но другой".
Хотя цель благая вроде.
Им наконец надоело стрелять себе в ногу всякими там memset'aми.
Хм, либо Windows достигла критической точки, когда тех долг уже настолько большой, что развивать систему становится настолько сложно, что проще переписать ее часть. Либо ...
И ещё как.
«Hi Ryan Levick here. Microsoft is not moving away from Rust. Verona is a research project to explore different memory safety models for systems programming. Verona is in part inspired by Rust (as well as pony and C#). It is not a fork of Rust or meant as a Rust replacement. It’s very early days in Verona’s development and hard to say what it’s future will be. The hope is to learn from Rust and if possible contribute back learnings into the language. This isn’t a zero sum game. The talk linked to in the CDNet article should hopefully clarify things. That article was very misleading. (https://www.reddit.com/r/rust/comments/e5kjyr/more_info_on_micrsoft_moving_away_from_rust/)»
Microsoft создаёт новый язык программирования, основанный на Rust