Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
auto в с++ и подобные вещи, оригинальная статья была написана в 2011 году.Я не касался функционального программирования на Scala, для этого нужно сравнивать Scala с другими функциональными языками, он я не FP'шник (FP guy)
Есть всё же несколько вещей, которые мне не понравились, за чуть более чем шести летний опыт работы со Scala.
Вывод типовScala:
val aGuy = "John"
auto theGuy = "Ivan";
Упрощенное определение классовScala:
class Person (val firstName:String, val lastName:String)
C++: struct Person{ std::string firstName; std::string lastName; }; // мне лично такой стиль форматирования не нравится
Преимуществ не видно.Объединение методов и операторовИзвините, но я не наблюдаю описанных проблем в С++
ListBuffer(1,2,3) append 4
или
ListBuffer(1,2,3) += 4
C++ (Qt5): (QList<uint64_t>{1, 2, 3}) << 4;
(QList<uint64_t>{1, 2, 3}).append(5);
(QList<uint64_t>{1, 2, 3})+=6;
Вообще говоря, += выглядит сомнительно, в контексте какого-нибудь алгоритма иногда можно понять по-другому."Mary" with "a purse" and "red shoes" should look "nice", стало доходить, что может быть на самом деле, речь об отсутствии точек и скобочек. Выглядит круто, но только если очень хорошая подсветка синтаксиса, иначе тяжело разобрать что есть что. Тем не менее чего-нибудь такого или типа linq в C++ не хватает.Person("Marry").with("purse").with("shoes").should(Look("nice"));
<troll-mode>Что скажут любители функциональных языков?</troll-mode>ТипыВ C++ вопрос контрвариации и ковариантности действительно не прост, возможно, по этому его как-то неявно избегают, и большой проблемы не ощущается.
Только конструкторы?Не совсем понятно о чем речь, вроде ничего сложного тут нет.
case Person(first,last) => println (" name is " + first + " " + last)
template<typename OS>
OS& operator<<(OS& os, const Person& p) {
return os << p.first << p.last;
}
Вообще эта фича «скалы» выглядит страшновато.auto уже было.const, пожалуйста, пусть будетstruct Person{ const std::string firstName; const std::string lastName; };
— Чем помогают геттеры и сеттеры, сгенерированные компилиятором?— Чем помогают геттеры и сеттеры, сгенерированные компилиятором?Anyway, всегда можно нагородить макрос, который и поле объявит, и соответствующие геттеры/сеттеры :)
почему нельзя отсортировать массив структур с readonly-полями
вместо физического копирования он копирует значения структур. Но это же бред какой-то…
Далеко не всегда имеет смысл хранить в массиве/векторе указатели на объекты, а не сами объекты...
Потому что в Java/C# экземпляры классов всегда передаются по ссылке (в терминологии C++ это указатель).
struct MyStruct
{
public readonly int X;
public readonly int Y;
public MyStruct(int x, int y)
{
X = x;
Y = y;
}
}
struct). И тем не менее, следующий код отработает безо всяких ошибок: MyStruct[] structs =
{
new MyStruct(10, 20),
new MyStruct(50, 35),
new MyStruct(35, 100),
};
Array.Sort(structs, (a, b) => a.X.CompareTo(b.X));
Array.ForEach(structs, a => Console.WriteLine("{0} {1}", a.X, a.Y));
>экземпляры классов
это кто вам такое сказал? Вот создал структуру с неизменяемыми полями:
И тем не менее, следующий код отработает безо всяких ошибок:
var x = new MyStruct(1, 0);
x = new MyStruct(2, 3);
Честно говоря, это я не понимаю, почему вот такой код компилируется
var x = new MyStruct(1, 0);
x = new MyStruct(2, 3);
X не привязана жестко к области памяти
если у меня ещё не случилось помутнение рассудка, в C++ та же фигня
struct point
{
const int x;
const int y;
};
int main()
{
point x = {1, 0};
point y = {2, 3};
x = y;
return 0;
}
error: cannot define the implicit copy assignment operator for 'point', because non-static const member 'x' can't use copy assignment operatorВ плюсах const означает (грубо) «участок памяти, занятый объектом, не должен модифицироваться».
В шарпе, видимо, readonly означает «нельзя изменить это поле, но можно переприсвоить весь объект целиком, подифицировав память».
никаких преимуществ не заметил
Конечно не заметили. Вы же статью прочитали «по диагонали». И тут же не к месту набросились со своим С++.Во-первых, тон статьи говорит о том, что посмотрите как это легко в Scala и как сложно в C++ или Java, там уж точно придется написать две стриницы кода. Я же, сомневаюсь в такой категоричности. Во-вторых, это не я придумал сравнивать с C++, а автор статьи.
SBT. Это всегда сложно. Серьезно, если вам нужно сделать что-то выходящее за рамки типичной работы с SBT, то вы попали. Существует столько разных не очевидных DSL, что Google будет сходить с ума пытаясь найти для вас как нужно сделать то, что вам нужно. Им нужно было сделать либо какой-то отдельный синтаксис, наподобие JSON или какой-то свой внутренний DSL, который компилятор / IDE мог бы понимать и помогать при работе с SBT.Абсолютно всё в sbt можно писать и без DSL. Документация просто шик, API удобный, возможностей куча.
И в Java и в C++ шаблоны имеют определенное зашитое ограниченное поведение (т.е. ковариантность)Не знаю, как в C++, но в Java generic'и инвариантны. Для получения ковариантного/контравариантного поведения используются wildcards. Массивы в Java, кстати, ковариантны.
Для получения ковариантного/контравариантного поведения используются wildcards.
но в Java generic'и инвариантны
List<String> не является не сабтипом или супертипом List<CharSequence>.class Arrays {
public static <T> List<T> asList(T... a)
}
является инвариантным по результату. Т. е. нельзя, скажем, написать String[] args = ...;
List<CharSequence> l = Arrays.asList(args); // оно же Arrays.<String>asList(args)
но можно List<String> l = Arrays.asList(args); // оно же Arrays.<String>asList(args)
или List<CharSequence> l = Arrays.<CharSequence>asList(args);
т. к. массивы являются ковариантными.String join(Collection<? extends CharSequence> cs) {
StringBuilder sb = new StringBuilder();
for(CharSequence c: cs) {
sb.append(c);
}
return sb.toString();
}
Он ковариантен по аргументу cs, т. е. готов работать как на коллекциях CharSequence, так и на коллекциях подтипов CharSequence (например String).cs порождает CharSequence, т. е. является producer'ом.val tomorrow = today + 1 dayval tomorrow = today + (1 day)
val tomorrow = today + 1.day
case class CDate(ms: Long) {
def +(i: Long) = new {
def day = CDate(i * 1000 * 3600 * 24 + ms)
}
}
val now = CDate(System.currentTimeMillis())
val nowWithDayAdded = now + 1 day
val someTimeInFuture = now + 1 day + 1 day
val someTimeInFuture = now + 1 day + 1 day
val nowWithDayAdded = now + 1 day
println(nowWithDayAdded)
[ant:scalac] /home/nasledov/projects/godoftime/User/src/main/scala/timetest/Main.scala:16: error: recursive value nowWithDayAdded needs type
[ant:scalac] println(nowWithDayAdded)
[ant:scalac] ^
[ant:scalac] /home/nasledov/projects/godoftime/User/src/main/scala/timetest/Main.scala:15: error: timetest.Main.CDate does not take parameters
[ant:scalac] val nowWithDayAdded = now + 1 day
[ant:scalac] ^
import scala.language.postfixOps
И в Java и в C++ шаблоны имеют определенное зашитое ограниченное поведение
List<T super Person> в Java уже отменили?вы будете и си называть препроцессором ассемблера?
case class Person(name: String, age: Int)
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public equals(Person other) {
return other.name.equals(this.name) &&
other.age == this.age;
}
@Override
public String toString() {
return "Person(" + name + ", " + Integer.toString(age) + ")";
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + name.hashCode();
hash = hash * 42 + age;
return hash;
}
public Person copy() {
return this;
}
public Person copy(String name) {
return new Person(name, this.age);
}
public Person copy(int age) {
return new Person(this.name, age);
}
public Person copy(String name, int age) {
if (name.equals(this.name) &&
age == this.age) {
// prevent new non-uniq object of immutable
// data structure from being created
return this;
} else {
return new Person(name, age);
}
}
}
// не знаю как вы, а я вспотел и почувствовал "глубокое внутреннее удовлетворение от продуктивно проведенного рабочего дня"
// ...чтобый прийти на следующий день, проверить что нигде не накосячил и обложить это все тонной тестов.
// можно так
x = x + 1
// а можно так
x += 1
try (InputStream is = file.openStream()) {
// do something
}
InputStream is = null;
try {
is = file.openStream();
// do something
} finally {
if (is != null)
is.close();
}public class Person {
public final String name;
public final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
if (age != person.age) return false;
if (!name.equals(person.name)) return false;
return true;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Person {
public final String name;
public final int age;
}
OMG Scala is a complex language!