Pull to refresh

Comments 61

Презентацию можно было не включать, пожалуй. Очень многое поменялось в языке с 2011.

Надеюсь, язык стабилизируется и обретёт бОльшую популярность. Много интересных решений при его создании принято. В свободное время решаю простецкие задачи с Rosettacode на Rust.

Ещё материалы:

Был ещё один интересный блог, в одной записи автор реализовал комплексные числа на основе traits. Ссылку я потерял. Нашёл: комплексные числа, записи с меткой «Rust».
>>traits. Ссылку я потерял
Какие traits? Те самые что в C++? Если да, то очень прошу найти ссылку!!!
Нет же, те самые что в Rust. Ссылка сразу после фразы "Ссылку я потерял. Нашёл:".

<далее не по комментариюEvilsInterrupt>
Обновил программку, определяющую предел глубины рекурсии, под новую версию Rust.
fn recursion(n: int) {
        println!("deep: {:d}", n);
        recursion(n + 1);
}

fn main() {
        recursion(0);
}

Позабавило сообщение об ошибке в новой версии.
Rust 0.8 падал с Segmentation fault на значении 7892, Rust 0.9 выдаёт эдакое:
Скрытый текст
deep: 12952

There are not many persons who know what wonders are opened to them in the
stories and visions of their youth; for when as children we listen and dream,
we think but half-formed thoughts, and when as men we try to remember, we are
dulled and prosaic with the poison of life. But some of us awake in the night
with strange phantasms of enchanted hills and gardens, of fountains that sing
in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch
down to sleeping cities of bronze and stone, and of shadowy companies of heroes
that ride caparisoned white horses along the edges of thick forests; and then
we know that we have looked back through the ivory gates into that world of
wonder which was ours before we were wise and unhappy.

fatal runtime error: assertion failed: !ptr.is_null()
Aborted
Простите, что лезу с неуместными сравнениями с другими языками… :)

// test.go

package main

import "fmt"

func recursion(n int) {
	fmt.Println(n)
	recursion(n+1)
}

func main() {
	recursion(0)
}


Запускаем:

$ go run test.go | tail
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x1646a0)
	/usr/local/go/src/pkg/runtime/panic.c:464 +0x69
runtime.newstack()
	/usr/local/go/src/pkg/runtime/stack.c:295 +0x3bc
runtime.morestack()
	/usr/local/go/src/pkg/runtime/asm_amd64.s:225 +0x61

// ... урезанный stack trace от собственно функции recustion

exit status 2
9277301
9277302
9277303
9277304
9277305
9277306
9277307
9277308
9277309
9277310


Без офигительных историй, зато ошибка при бесконечной рекурсии более, чем узнаваема — «stack overflow» :).
На канале #rust irc.mozilla.org мне пояснили, что на самом деле программа должна выдавать task '<main>' has overflowed its stack. Если закомментить println, так и происходит. Видимо, переполнение происходит именно в println и это не перехватывается.
А сравнивать можно здесь: rosettacode.org/wiki/Find_limit_of_recursion
Видео с конференции linux.conf.au 2014, закончившейся вчера. «The Rust language: memory, ownership and lifetimes»
Да, раст с каждой новой версией становится всё стабильнее и удобнее в использовании. Хоть там и есть много довольно неоднозначных решений, мало библиотек и нет пока нормальной сборочной инфраструктуры, всё равно у него, на мой взгляд, большой потенциал. Он попадает, фактически, в незанятую нишу высокопроизводительных высокоуровневых языков, где сейчас только C++ и есть. Ну может D ещё.
и Го, который чем-то похож на Rust, но что-то особой популярности пока не сыскал.
Стоит отметить, что его популярность всё же неплохо растёт.
Что за график? Я сужу больше по к-во статей, проектов, с которыми сталкиваюсь и компаниях, где его используют в продакшене ну или хоть как-то. И тут пока все тухло, даже статей мало выходит, а проектов и компаний вообще практически нет.
Так и релиза не было, никто не будет использовать альфа версию в продакшене ;)
Если вы про Go, то он зарелизился уже давно. Скоро уже будет 1.3 версия.
Извиняюсь за невнимательность, показалось что речь про Rust
Популярность поискового запроса «golang».
Мало компаний? А как же неделя статей на хабре про «мы переписали всё на Go и теперь у нас всё работает в 20 раз быстрее» или чем вам Google не компания? У них часть сервисов на Go работает, собственно и разрабатывали его для собственного применения, так как другие языки не справлялиль при равных трудозатратах. Какая именно часть не говорят, но точно сетевые и высоконагруженные проекты.
Плюс опять же Google App Engine.
Плюс code.google.com/p/go-wiki/wiki/GoUsers
Я читал эту «неделю статей» (одну вроде, или было больше)? кроме того, что она сомнительная, это очень редкий пример. Что работает в гугле на Го непонятно, какие-то узкоспециализированные мелочи, возможно.

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

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

Сравните с тем, как продвигался тот-же Руби в свое время. Или C# (и другие шарпы)
Простите, что упомянул МС)
Фигасе не сыскал, еще как сыскал! Я вот попробовал и на го и на раст, остался на первом!
Получается эта таже ниша что и у Go? А как rust в сравнении с Go lang?
Оба нацелены на многопоточное программирование. На Rust ничего не делал, но знаком с Go.
Go мне кажется более… продуманным, наверное. Так как каждая особенность языка проходит жутко строжащий контроль перед тем как быть внедрённой в язык. Плюс разные приятные мелочи — быстрая компиляция, набор утилит для работы с ним (go fmt, go test, go get), наличие весьма неплохих web фреймворков делают его очень приятным в работе.
А от связки Google App Engine + Go я просто в восторге.
ВЫ забыли упомянуть такой прикольный нюанс как go fix. Такого тщательного подхода к смене языка ни в одном другом языке нету. Этак команда берет на вход файл и пытается фиксить под текущие реалии языка.
Нет. Go — это язык с обязательной сборкой мусора, он не может использоваться в сильно низкоуровневых приложениях. Rust может, потому что там сборка мусора опциональна. Плюс у Go весьма хреновая встраиваемость в другие приложения (и поддержка модульности тоже). О чём речь, Go до сих пор не может генерировать нормальные разделяемые библиотеки. А Rust с самого начала одной из целей имел интероперабельность с C. Растовый FFI — один из лучших FFiев, которые я видел.
Сборку мусора можно отключить в Go, это конечно не free() из С, но всё равно помогает для интенсивных участков кода.
Shared libraries ещё не сделали, но не вижу в этом такой большой проблемы (мы же пишем на Go всё таки). Я думаю сделают когда-нибудь.
Если сборку мусора в Go отключить полностью (как и в D, например), мы получим тонну нерабочих библиотек. А в Rust изначально идиоматично написание кода, который не использует GC, и, например, вся стандартная библиотека там от сборки мусора не зависит. Если сторонние качественные библиотеки пишутся без сборщика мусора — а именно так и происходит, и будет происходить дальше, скорее всего, — то при создании уже конечных программ у вас будет выбор, использовать GC или нет, и при отказе от неё ничего не отвалится.

А насчёт разделяемых библиотек — это как раз очень важный пункт, из-за которого ниши Rust и Go пересекаются весьма условно. На Go вы не сможете написать даже плагины к своему приложению никак, кроме как через IPC, что не всегда удобно и даже возможно. Плюс из-за этого же библиотеки на Go вы не сможете нормально подключать к программам на других языках, опять же, без использования средств IPC. Я не говорю, что это безусловно плохо — с точки зрения архитектуры это может быть даже и хорошо, потому что поощряет написание слабо связанного кода, но, тем не менее, из-за таких вещей области применения языков достаточно различны.
Или вот, например, шедулинг. В Go всегда применяется модель n:m, и вы не можете контролировать, какой поток ОС какой горутине принадлежит. А в расте у вас есть выбор (как раз с 0.9 появился) — вы можете выбрать libgreen и получить шедулинг легковесных потоков повер потоков ОС и соответствующее IO, либо вы можете подключить libnative и получить стандартные потоки операционной системы (также с соответствующим IO). И этот выбор может быть достаточно важным, например, в реалтайм- или эмбеддед-системах.
Убедили. Много отличий.
Кстати, в Go всё же можно попросить runtime использовать выделенный тред для соответствующей goroutime с помощью runtime.LockOSThread(). Другое дело, что, насколько я знаю, нельзя включить режим, когда все goroutine будут работать в отдельных тредах. Но вообще, да, со встраиваемостью у Go всё очень плохо — сильно сказывается изначальная ориентированность языка на «systems programming language», или, переводя на русский, на написание демонов :).
Ну всё-таки «systems programming language» — это не написание демонов, а системное программирование — драйверы там, ОС, низкий уровень и прочее. Демоны и системное программирование могут пересекаться, да, но это не одно и то же. И вот как раз Rust к «systems programming» ближе, чем Go)
Кто Вам сказал что нельзя отключать GC?
Из Package runtime(http://golang.org/pkg/runtime/):
>>Setting GOGC=off disables the garbage collector entirely.
Ок, неправильно сформулировал. Можно, но это нужно делать только в крайних случаях. Go рассчитан на работу при включённом GC, и никаких средств (естественно, кроме аналогов malloc/free) для работы с памятью не предусмотрено, и, естестенно, подавляющее большинство библиотек полагается на GC.
Я не говорю, что это плохо — я сам программирую на Java, а мой любимый язык — Scala, но просто в Rust можно и нужно жить без GC, и это совершенно не трудно, а в Go — практически невозможно. Я только это и хотел подчеркнуть.
Для меня сейчас в Golang только один недостаток: Это результирующий executable. Получается такой файл на выходе, что мне его строение не понятно ((( В виду того что пишу различные протекторы исполняемых файлов мне очень важно понимать что же собственно внутри файла. А там, в exe-файле после компиляции, чуть ли не ВСЕ рассказано о том как получить исходный код и как работает файл! ;((( Т.е. reverser-engineer-у не доставит труда догадаться о тех алгоритмах, которые я бы не хотел показывать
Да, есть такое дело. Это из-за отражения. Вроде бы даже бинарники на Go нежелательно подвергать stirp'у, а то могут сломаться библиотеки, которые пользуются отражением.

Кстати, это один из минусов раста пока что — отсутствие отражения в принципе. По крайней мере, я пока не видел, как его использовать. Другое дело, что с наличием трейтов как в расте не так уж и часто оно и нужно.

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

Мне не хватает C++ идиомы traits. К примеру при работе с PE форматом понимая что все заголовки формата разделяются на 32 и 64, но названия заголовков, название полей, их расположение все одинаковое. Отличие только в типах. Так вот traits мне позволяет писать только одну типу кода, а далее в коде написать что-то вроде:

if ( pe::isPeImage(stream) ) {
pe::Image image(stream);
processImage(image);
} else {
pe::Image image(stream);
processImage(image);
}

В Golang же приходится писать 2 ветки кода, для 32 и 64 бита отдельно! ;(((
Вы не рассматривали возможность написания критичного к ОС (и декомпиляции) кода на C? С помощью cgo всё это компилируется в один бинарник, причём возможны вызовы C-функции из Go и наоборот.
Да я только только начал читать godoc cmd/cgo ))) Мне хочется протащить популярную библиотеку дизассемблирования Mediana в Golang )))
Go как язык гораздо более примитивный, чем Rust. Если проводить параллели, Go это как статически типизированный компилируемый Python. А в Rust явно питались идеями из C++ и Haskell.
Перечитал сейчас обновленную документацию Rust. Он мне кажется переинженереным что ли. Да, Go простой, и С простой и Haskell простой. А вот C++, Rust, Scala перебор плохо увязанных абстракций и методологий. Это, разумеется на мой вкус.
Haskell не простой. Я не смог до конца осилить алгебру типов на уровне расширений GHC.
Да, по какой-то причине при первом прочтении документации Rust кажется именно что переинженереным. Но когда попробуешь на нём что-нибудь написать и когда поймёшь идеологию языка и его основные паттерны, то это ощущение гарантированно пропадает. Иногда даже становится непонятно, как без некоторых вещей живут в других языках :) Со Scala, кстати, то же самое, даже ещё в большей степени. Но в Scala совершенно необязательно знать и применять самые сложные вещи вроде path-dependent types или higher kinds. Не так давно читал краткую статью про уровни Scala-программистов, но ссылку потерял уже :( там это как раз объяснялось.
По-моему мультиязычность играет против человечества, в скором будущем не возможно будет установить лидера в языках, как такового, а выбор будет сделан под конкретную задачу. Дети и студенты, которые будут стремится всё изучать не смогу объективно мысли из-за неподготовленности мозга к такой огромной нише информации, они попросту не смогут пройти весь путь и получить полное представление о концепциях языка.
Странно, почему написано что он визуально похож на С. Не вижу ничего похожего, даже близко. Если говорить о визуальной похожести, то скорее OCaml, может даже Ruby или Python с фигурными скобками. Но уж никак не C.
Мне в этом языке не понравилась обработка ошибок. Слишком усложнена ((( Я читал всего лишь один док The Rust Condition and Error-handling Guide(http://static.rust-lang.org/doc/master/guide-conditions.html). Пытался привыкнуть, но не получилось. Обработка ошибок в Golang куда более ясная:
1) Если обычная ошибка, То возвращай error
2) Возвращай тип error последним!
3) Если уж вообще Ахтунг, то дергай panic()
4) Если кто-то в сторонней либе дергает panic(), а ты у себя в коде знаешь как выкрутиться, то дергай recover()

Не знаю, может просто готовить не научился и следует еще глубже погрузиться. Хотя не люблю вещи, которые требуют большего погружения, когда есть решения сделать вещи проще!
Обработка ошибок в Rust — смесь разных подходов из функциональных языков. Там на самом деле ничего сложного нет.

1. если функция может вернуть как успешный результат, так и ошибку, причём нам не важна конкретная ошибка (или ошибка может быть только одна — вроде отсутствия ключа в мапе), то нужно использовать Option — это как тип Maybe в хаскелле или Option в Scala;

2. если функция может вернуть как успешный результат, так и ошибку, причём конкретная ошибка важна, и разные виды ошибок нужно обрабатывать по-разному (например, файл нельзя открыть из-за неправильно указанного пути или нет прав на это), то нужно использовать Result<T, E> — это как тип Either или монада Error в Haskell или Either/Try в Scala;

3. если произошло что-то совсем терминальное, и нет никакого способа восстановить нормальную работу задачи, то нужно использовать fail!() для обваливания текущего потока. Это что-то типа неотлавливаемых внутри потока исключений — снаружи потока их можно отловить и обработать. Это похоже на процессы Erlang;

4. если произошла ошибка, после которой всё же можно продолжить, но произошла она в глубине кода и продолжать тоже нужно там же, а не экстренно завершаться, то нужно использовать conditions. Тут немного трудно придумать краткий пример, можно посмотреть описание кондишнов в документации. Кто знаком с Common Lisp, сразу поймёт о чём речь, хотя в Rust кондишны немного послабее, чем в CL. По сути, это такие исключения, обработчики для которых ставятся снаружи кода, который может получить ошибку, но выполняются непосредственно по месту ошибки. Если ни один обработчик не установлен, получаем пункт 3. Это довольно интересная концепция, непривычная после обычных развёртывающих стек исключений.

Как видите, тоже четыре пункта :)

Блин, хабр почему-то не понимает нумерованный список :(
Про Ваш «Блин»:

Нумерованный список;

По обработке ошибок:
А что делать если мне нужно сохранить историю возникновения ошибки? Т.е. вектор ошибок, как в этом случае поступают в Rust?

Ну к пример веду работу с ELF форматом и вызываю функцию isCheckElfExecutable() которая в недрах своего кода дергает IO-операцию read() из стрима во время которой возникла ошибка. Сама по себе «Ошибка чтения» конечно важна, Но не настолько как ее источник, к примеру на одном верхнем уровне не правильно вычислили смещение в стриме где обычно распологается сигнатура.

В ОО-подходе принято бросать исключение, а в верхних слоях можно получить стектрейс и на этом вся информация для отладки получена. Как же в Rust это решается?
Насколько я понимаю, к сожалению, сейчас со стектрейсами всё не очень радужно. Если возникает ошибка, приводящая к раскрутке стека и завершению таски, то мы увидим только то место, где она произошла — имя файла и строку, без стектрейса. Правда, у меня такое ощущение, что так происходит из-за того, что я не совсем правильно собрал сам компилятор. Странно, но я не могу найти упоминаний про проблемы со стектрейсом в интернете. Есть пара упоминаний годичной давности про проблемы со стектрейсом, если LLVM собран не с теми флагами, но я хз насколько информация актуальна. Спрошу в списке рассылки, наверное.

Насчёт стектрейсов в кондишнах — это вряд ли возможно, потому что их обработка не приводит к раскрутке стека. Но вы можете передавать в обработчики произвольные даные (и получать обратно тоже), это должно скомпенсировать проблему.
Решил свою проблему. Напомню проблему:
>>Сама по себе «Ошибка чтения» конечно важна, Но не настолько как ее источник, к примеру на одном верхнем уровне не правильно вычислили смещение в стриме где обычно распологается сигнатура.
Т.е. когда процесс вычисления идет примерно так:
func1() ->
..func2() ->
....func3() — тут возникла бага

то нам важно не только то что где-то в программе возникла ошибка, но и почему она возникла. Стектрейс в golang можно получить с помощью пакета Runtime и функций: runtime.Caller( тут глубина вызова ) и runtime.FuncForPC( тут некий pc про него читать в доке ).Name()
Читая п.4 про кондишены мне это очень напоминает генераторы в Python, когда мы из глубины вычисления дергаем yeld() возвращая текущий результат и потом возвращаемся к тому же месту после того как наш результат обработали.
Ну кондишны это тоже форма нелокальной передачи управления, как и генераторы, но всё же это немного другое и для других целей.
Я думаю Вам стоит написать мануал по Rust на тему обработки ошибок при разработке на этом языке.
Да я пока только язык изучаю, кондишны вот, например, ни разу ещё не использовал) но идея хорошая, спасибо. Может, и в самом деле что-нибудь про Rust напишу, как будет время…
Есть ли примеры полноценных программ написанных на Rust?
Тест-кейс «Поиск исходного кода на rust»

Процедура:
1) ввести в адресную строку github.com и нажать на Enter
2) Увидеть надпись Explore нажать на нее
3) В строке поиска набрать «rust» и нажать Enter

Ожидается:
Число большего или равного в надписи подобной этой: «We've found 1,127 repository results»
Scheme и вобще диалекты LISP довольно просто реализуются, почему бы не написать свой да на новом языке?

В README к репозиторию указано, что идея взята у Питера Норвига с его проектом lispy — интерпретатор lisp на python в 113 строк. Норвиг, кстати, очень продвинутый дядька. Много интересных публикаций и постов.
Sign up to leave a comment.

Articles