Алсо у скалы сейчас есть некоторые проблемы, и тащемта пофиг в рамках какого проекта они будут решены. Главное, чтобы форк не повторил судьбу ffmpeg/libav.
Окамл не взлетел ровно настолько же, насколько и скалка.
Даже если бы это было так (хотя это не так), Окамлю для этого понадобилось на 10 (или 15?) лет больше. Мне нравится Окамль, но он бесперспективен ИМХО).
Ты не указал конкретных недостатков. Главная практическая претензия к шаблонам Си++ - они ломают раздельную компиляцию. Вторая - сложность (и ненужность пресловутой Тьюринг-полноты). Ты оба этих недостатка нашел в Rust? Ну а про «недостатки полиморфных функций ML» - звучит круто, да.
Главная практическая претензия к шаблонам Си++ - они ломают раздельную компиляцию.
У кого как.
У меня главная претензия в том, что полиморфные функции Rust всегда мономорфизуются для каждого используемого типа. Из-за этого можно напороться на «бесконечное развёртывание шаблонов» (это в плюсах; как оно в Rust называется я не помню, но суть та же).
Честно говоря, не знаю, что они там сделали для раздельной компиляции, но, думаю, ничего хорошего (учитывая, что для новых типов функцию тоже надо мономорфизовать).
Ну а про «недостатки полиморфных функций ML» - звучит круто, да.
Ну да. Полиморфную функцию в стиле ML нельзя руками «потвикать», чтобы она для каких-то типов работала чуть иначе. Конечно, для ML оно и не нужно; а вот для языка системного программирования, которым выставляет себя Rust — дело другое.
Главная практическая претензия к шаблонам Си++ - они ломают раздельную компиляцию.
У кого как.
Интересно мнение среднего Си- или Си++-программиста.
можно напороться на «бесконечное развёртывание шаблонов» (это в плюполиморфные функции Rust всегда мономорфизуются для каждого используемого типа. Из-за этого можно напороться на «бесконечное развёртывание шаблонов» (это в плюсах; как оно в Rust называется я не помню, но суть та же).
Поскольку это выясняется на этапе компиляции, это не такая уж проблема.
Полиморфную функцию в стиле ML нельзя руками «потвикать», чтобы она для каких-то типов работала чуть иначе. Конечно, для ML оно и не нужно; а вот для языка системного программирования, которым выставляет себя Rust — дело другое.
Я недостаточно знаю Rust и поэтому спорить не стану, но мне кажется, что через трейты и impl-ы это можно сделать.
Пока Самсунг и Мозилла финансируют разработку, не сильно важно, какие у них планы на Servo.
Почему главный?
этот язык начали пилить только для того, чтобы написать на нем servo.
Глупости. Язык начал пилить Грейдон Хоар именно как современный язык системного программирования. Потом Mozilla Research решила, что он подойдет им для Servo. А потом вокруг языка начало складываться сообщество людей, которые применяют его для чего попало.
Почему браузер - плохой стенд для отработки языка системного программирования?
потому что браузер - не системное ПО.
А то, что все распространенные браузеры написаны на языке системного программирования - это просто совпадение, да.
операционные системы, ядра или компоненты, написанные на javascript, php
Над тобой пошутили, а ты и повелся.
java и C#
Если бы ты учился немного лучше, ты бы знал, что это были диалекты Java и C#, специально приспособленные для системного программирования. И всё равно, ОС на них остались игрушками исследователей.
В своё время я об этом заводил баг — мне прямым текстом сказали, что мономорфизация в Rust by design и нефиг раскачивать лодку. Правда, это было несколько месяцев назад — но недавно мне в уши надули, что, якобы, появились настоящие дженерики, и я попробовал заново.
struct Nil;
struct Cons<T> {
head : int,
tail : T
}
trait Product {
fn product(&self, other: Self) -> int;
}
impl Product for Nil {
fn product(&self, _other: Nil) -> int {0}
}
impl<T : Product> Product for Cons<T> {
fn product(&self, other: Cons<T>) -> int {
self.head * other.head + self.tail.product(other.tail)
}
}
fn genprod<T : Product>(x : T, y : T, n : int) -> int {
match n {
0 => x.product(y),
_ => genprod(Cons {head : n+1, tail : x}, Cons {head : n*n+2, tail: y}, n-1)
}
}
fn essence(n : int) -> int {genprod(Nil, Nil, n)}
fn main() {
println!("{}", essence(5));
}
Ну и получил, соответственно,
test.rs:17:1: 22:2 error: reached the recursion limit during monomorphization
test.rs:17 fn genprod<T : Product>(x : T, y : T, n : int) -> int {
test.rs:18 match n {
test.rs:19 0 => x.product(y),
test.rs:20 _ => genprod(Cons {head : n+1, tail : x}, Cons {head : n*n+2, tail: y}, n-1)
test.rs:21 }
test.rs:22 }
невозможность писать «специализации» полиморфных функций.
Ну дык на том стоит ML — дженерик-функция пишется один раз, и работает со всеми возможными типами. И в Rust всё точно так же.
Другой вопрос, что:
1) Компилятор (не обязательно rust) в НЕКОТОРЫХ СЛУЧАЯХ использует специализированную функцию — скажем, GHC вообще этим знаменит, он буквально для каждой полиморфной функции старается нагенерить побольше специализаций. Но этот процесс никак не контролируется программистом и вообще снаружи не виден (кроме того факта, что некоторые функции работают чуть побыстрее).
2) Есть возможность (используя всякие фокусы типа overlapping instances) сделать иную реализацию тайпкласса (это уже чисто Haskell-specific, ни Rust, ни ML-языки тут ни при чём). Типа
data T a = ...
class C x where ...
instance C (T a) where ...
instance C (T Int) where ...
В этом случае, если функции из тайпкласса C используются для типа T Int — то будет использоваться вторая реализация.
Однако, тут есть ловушка, которую не все понимают (и регулярно попадаются). Выбор инстанса производится на стадии компиляции. То есть, если использовать функцию из класса C в ситуации, когда конкретный тип неизвестен (и не может быть определён исходя из типов аргументов), то вне зависимости от того, окажется там на самом деле Int или что-то другое — выбрана будет общая реализация.
То есть, вот такой код:
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, OverlappingInstances #-}
module Main where
data T a = T a
class C x where c :: x -> Int
instance C (T a) where c _ = 0
instance C (T Int) where c (T n) = n
data E = forall a. E a
test :: E -> Int
test (E a) = c (T a)
main =
do print $ c $ T (4 :: Int)
print $ test $ E (4 :: Int)
выведет
4
0
То есть, мы не можем утверждать, что для типа Int всегда работает специализированный вариант. Работает, но только в простых случаях.
Круто, в кой-то веке интересная критика Rust`а, а не тупые крики «ненужна патамушта с++» и все в таком духе.
Честно говоря, не знаю, что они там сделали для раздельной компиляции, но, думаю, ничего хорошего (учитывая, что для новых типов функцию тоже надо мономорфизовать).
... Полиморфную функцию в стиле ML нельзя руками «потвикать», чтобы она для каких-то типов работала чуть иначе. Конечно, для ML оно и не нужно; а вот для языка системного программирования, которым выставляет себя Rust — дело другое.
Гм, я никогда не думал, что это можно рассматривать как недостаток, всегда считал просто особенностью «бесплатных» (не сказывающихся на времени выполнения) обощенных функций. А как вообще можно добиться реализации обощенных функций, как ты хочешь, без накладных расходов во время выполнения программы? В каком языке-компиляторе оно есть?
Ну, я не сказал, что я этого так уж хочу. Я низкоуровневым программингом стараюсь не заниматься. Просто, если уж речь зашла о темплейтах и дженериках, не надо создавать впечатление, что одно - подмножество другого, это не так.