Бластеры в SW — это не лазерное оружие, а плазменное.
Правда, турболазеры и прочие пушки большего калибра, вроде как, позиционируются как лазерные, и медленная скорость выстрелов в их случае действительно необъяснима.
Кстати, какова эффективность (по сравнению с исключениями на современных архитектурах и компиляторов) у такого подхода? Накладных расходов на каждый успешных вызов функции нет?
Если вы говорите про подход с обработкой ошибок с помощью Result, то накладные расходы здесь гораздо меньше, чем у исключений. Фактически, накладной расход — это дополнительное поле-дискриминатор enum'а в возвращаемом значении, и всё.
Про checked exceptions пишут следующее:
«Checked exceptions are bad because programmers just abuse them by always catching them and dismissing them which leads to problems being hidden and ignored that would otherwise be presented to the user»
В Rust невозможно проигнорировать ошибку а-ля catch (Exception e) в Java. Если функция, которую вы вызываете, может завершиться с ошибкой, то её возвращаемое значение будет типа Result<T, Error>, из которого собственно T можно достать только явно, через паттернматчинг (ну или через конструкции, к нему сводящиеся — монадические комбинаторы или макрос try!()). Да, некоторые операции типа записи в поток ввода-вывода могут ничего не возвращать, и в таком случае возможность случайно проигнорировать ошибку возрастает, но компилятор в таком случае выдаст предупреждение.
Кроме того, представьте себе, что вам например нужно добавить в самую общую, всеми используемую библиотеку еще один тип ошибок который она должна выбрасывать (возможно ранее какие-то функции вообще не выбрасывали ошибок, а теперь должны). Теперь в Rust и в java вам придется пройтись по ВСЕМУ коду (стандартному, стороннему, своему) и везде изменить сигнатуры функций. Ну и до кучи все перекомпилировать конечно.
Это же Ад ломающий обратную совместимость.
Как правило, библиотеки, которые предоставляют функции, которые могут завершиться с ошибкой, содержат специальный тип-enum, варианты которого соответствуют ошибкам. В этом случае при добавлении новых ошибок сигнатура ни одной функции не поменяется. Клиентский код может сломаться там, где делается паттернматчинг по этому енуму, но это делается далеко не всегда — очень часто ошибки просто выводятся пользователю через реализацию Display для ошибки, без точного анализа.
Да, если изменяются функции, которые раньше вернуть ошибку не могли, а теперь могут, то это ломает обратную совместимость. В этом случае автор библиотеки соответствующим образом изменит версию своего проекта согласно semver, и Cargo обеспечит, чтобы код, зависящий на старую версию библиотеки, не сломался.
Object-oriented programming (OOP) is a programming paradigm based on the concept of «objects», which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.
Объектно-ориентированный язык так или иначе поощряет проектирование и программирование в терминах объектов и взаимодействия между ними. Если это не так, то язык не является объектно-ориентированным. Наличие полиморфизма (кстати, какого именно? Параметрического, ad-hoc, подтипов?), наследования и инкапсуляции не является ни необходимым, ни достаточным условием. Например, в Python инкапсуляция отсутствует в принципе — вы всегда можете добраться до чего угодно в любом объекте, но он от этого не становится менее объектно-ориентированным. И наоборот, ни Go, ни Rust не поощряют проектирование в ООП-терминах (объекты, классы, иерархии и прочее), поэтому они не являются ООП-языками.
Эти критерии не тождественны объектно-ориентированности. Например, в Go есть всё, что вы указали (окей, наследование с натяжкой), но он не является объектно-ориентированным. Когда в Rust добавят простое наследование структур (такие RFC уже есть), он тоже будет содержать все эти концепции, но он также не будет ОО.
By definition, it is the responsibility of the object, not the external code, to 'on-demand' select the procedural code to run/execute in response to a method call, typically by looking up the method at run time in a table associated with the object.
В данном случае вызов метода ничем не отличается от вызова обычной функции, потому что метод, по сути, функция и есть. Понимаете, то, что управление передано в метод, уже означает, условно говоря, что объект «получил» «сообщение». Посмотрите, как ООП реализовано в Smalltalk, например — это именно то ООП, которое изначально подразумевалось под этим термином.
Однако, на самом деле, это действительно просто вопрос терминологии. То, что под терминами подразумевается, постоянно меняется, и то, что C++ и Java на протяжении всего их времени жизни называли ООП-языками, сместило/расширило суть понятия ООП. Поэтому называть ООП-языками C++, Java и прочие, на мой взгляд, вполне приемлемо. Например, та же штука произошла, хоть и более быстро, с термином RESTful. Что только под ним сейчас ни понимают, но в 99% случаев это даже близко не напоминает то, что изначально подразумевалось в исходной работе, где этот термин был введён.
Собственно, я только против того, чтобы вызов метода называли отправкой сообщения, потому что по сути это не так.
Строго говоря, здесь нет обмена сообщениями. Здесь вызов функции, как в старом добром процедурном языке, просто выглядит иначе. Обмен сообщениями подразумевает, что та сторона, которой отправлено сообщение, сама решает, что делать с сообщением — например, может от него отказаться.
Сейчас метод to_string() определёт в трейте ToString, у которого есть blanket-реализация для всех Display-типов:
impl<T: Display> ToString for T {
fn to_string(&self) -> String {
format!("{}", self)
}
}
Соответственно, для String/&str также используется format!(), что неэффективно.
Как только специализация будет доступна, можно будет переопределить ToString для str через String::from_str(). Без специализации сделать такую реализацию нельзя, потому что она будет конфликтовать с blanket-реализацией для T: Display.
Я в курсе, что «наследование» трейтов на самом деле не наследование в смысле наследования классов/интерфейсов, например, в Java. Но это официальная терминология, см. например, здесь:
Хм, если вопрос только про стабильность, то стабильной она стала начиная с версии 1.0. Ломающих изменений в рамках 1.0 там быть не должно (исключая soundness-фиксы).
Для Telegram вроде бы есть десктопные клиенты с шифрованием, по крайней мере этот. На сайте, правда, английский немного странный, но сам проект даже выложен на гитхабе.
Я бы не советовал использовать usize в сигнатуре FFI-метода. В C нет непосредственного аналога usize. Лучше в этом случае взять lib::size_t, или вообще фиксированный тип.
Скорее не доктор, а кандидат. Требования к Ph.D вроде как ближе к нашему кандидату, а аналога доктора наук, вообще говоря, нет (только в некоторых странах).
Правда, турболазеры и прочие пушки большего калибра, вроде как, позиционируются как лазерные, и медленная скорость выстрелов в их случае действительно необъяснима.
Если вы говорите про подход с обработкой ошибок с помощью
Result
, то накладные расходы здесь гораздо меньше, чем у исключений. Фактически, накладной расход — это дополнительное поле-дискриминатор enum'а в возвращаемом значении, и всё.В Rust невозможно проигнорировать ошибку а-ля
catch (Exception e)
в Java. Если функция, которую вы вызываете, может завершиться с ошибкой, то её возвращаемое значение будет типаResult<T, Error>
, из которого собственноT
можно достать только явно, через паттернматчинг (ну или через конструкции, к нему сводящиеся — монадические комбинаторы или макрос try!()). Да, некоторые операции типа записи в поток ввода-вывода могут ничего не возвращать, и в таком случае возможность случайно проигнорировать ошибку возрастает, но компилятор в таком случае выдаст предупреждение.Как правило, библиотеки, которые предоставляют функции, которые могут завершиться с ошибкой, содержат специальный тип-enum, варианты которого соответствуют ошибкам. В этом случае при добавлении новых ошибок сигнатура ни одной функции не поменяется. Клиентский код может сломаться там, где делается паттернматчинг по этому енуму, но это делается далеко не всегда — очень часто ошибки просто выводятся пользователю через реализацию Display для ошибки, без точного анализа.
Да, если изменяются функции, которые раньше вернуть ошибку не могли, а теперь могут, то это ломает обратную совместимость. В этом случае автор библиотеки соответствующим образом изменит версию своего проекта согласно semver, и Cargo обеспечит, чтобы код, зависящий на старую версию библиотеки, не сломался.
Объектно-ориентированный язык так или иначе поощряет проектирование и программирование в терминах объектов и взаимодействия между ними. Если это не так, то язык не является объектно-ориентированным. Наличие полиморфизма (кстати, какого именно? Параметрического, ad-hoc, подтипов?), наследования и инкапсуляции не является ни необходимым, ни достаточным условием. Например, в Python инкапсуляция отсутствует в принципе — вы всегда можете добраться до чего угодно в любом объекте, но он от этого не становится менее объектно-ориентированным. И наоборот, ни Go, ни Rust не поощряют проектирование в ООП-терминах (объекты, классы, иерархии и прочее), поэтому они не являются ООП-языками.
В данном случае вызов метода ничем не отличается от вызова обычной функции, потому что метод, по сути, функция и есть. Понимаете, то, что управление передано в метод, уже означает, условно говоря, что объект «получил» «сообщение». Посмотрите, как ООП реализовано в Smalltalk, например — это именно то ООП, которое изначально подразумевалось под этим термином.
Однако, на самом деле, это действительно просто вопрос терминологии. То, что под терминами подразумевается, постоянно меняется, и то, что C++ и Java на протяжении всего их времени жизни называли ООП-языками, сместило/расширило суть понятия ООП. Поэтому называть ООП-языками C++, Java и прочие, на мой взгляд, вполне приемлемо. Например, та же штука произошла, хоть и более быстро, с термином RESTful. Что только под ним сейчас ни понимают, но в 99% случаев это даже близко не напоминает то, что изначально подразумевалось в исходной работе, где этот термин был введён.
Собственно, я только против того, чтобы вызов метода называли отправкой сообщения, потому что по сути это не так.
www.reddit.com/r/LinuxActionShow/comments/40oo3n/remixos_released_and_has_a_scary_eula/cyx80my
Into::into()
принимаетself
по значению, такие трейты не могут быть object-safe, следовательно, из них нельзя сделать трейт-объект.to_string()
определёт в трейтеToString
, у которого есть blanket-реализация для всехDisplay
-типов:Соответственно, для
String
/&str
также используетсяformat!()
, что неэффективно.Как только специализация будет доступна, можно будет переопределить
ToString
дляstr
черезString::from_str()
. Без специализации сделать такую реализацию нельзя, потому что она будет конфликтовать с blanket-реализацией дляT: Display
.(выделение моё)
Поэтому, так как
Copy
объявлен каквполне корректно говорить, что
Copy
наследуетClone
.file.delete()
иfile.mkdirs()
— это части устаревшего API. В NIO.2 ничего подобного, к счастью, нет.Хм, если вопрос только про стабильность, то стабильной она стала начиная с версии 1.0. Ломающих изменений в рамках 1.0 там быть не должно (исключая soundness-фиксы).
Не может быть! Если так, то это очень здорово! Не могли бы вы, пожалуйста, дать ссылку на это объявление? В гугле ничего не находится.