Как стать автором
Обновить
97
0
Семен Попугаев @senia

Пишу код и помогаю другим

Отправить сообщение
Вы в Питере живете? Если да, то вас не затруднит показать фото с испорченным видом?

Просто я ежедневно вижу эту башню начиная от Кантемировского моста и далее проезжая Ушаковскую набережную. Дальше ее с набережных просто не видно.
Кантемировский мост — это как раз там, где стоит трехсотметровая телевышка.
При других ракурсах на башню там вид на намывные территории и ЗСД.

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

Из центра на данный момент башня не видна с земли. С Исакиевского собора почти наверняка видна, но оттуда и порт с кранами видно. Пока там еще нет шпиля — после его монтажа может что-то и изменится, но изливать такие потоки яда по поводу столь отдаленного от центра здания пока преждевременно.
Если хотите написать о преимуществах scala, то надо с ними очень хорошо ознакомиться. Все-таки побить Dart на его поле (или хотя бы играть с ним на равных) можно только очень хорошо зная scala.
Лично я не настолько хорошо знаком с разработкой FE, чтоб писать такие статьи.
Есть возможность взять лучшее из 2 миров: есть отличная адаптация Learn You a Haskell for Great Good! для scala: herding cats.
Про Play 2 — если scala нравится как язык, то я бы порекомендовал akka-http — на мой взгляд это гораздо более scala way.
Презентация по scala.js от SAP. Возможно вам поможет.

Можно. Просто поддержки Java EE там нет, так что всё сам.
Еще там нет поддержки баз данных. И вообще много чего. Но работать вполне можно.
У вас какой бэкграунд?

Просто scala.js отлично подходит тем, кто уже залез в глубины scala и не готов расставаться. А вот для изучения… безумству храбрых поем мы песню =).

Преимущества scala.js проявиться могут либо в единой кодовой базе с BE на jvm, либо в хардкорном метапрограммировании, либо в не менее хардкорном FP с вложенными монадами и прочими прелестями. Еще опция — формализация вашей задачи и описание в виде DSL.
Для всего этого надо быть scala спецом, решившим покодить под FE, а не наоборот.

А вот что с нуля вам предложить как киллерфичу scala.js я даже не представляю.
Обращайтесь если что.

Function0 — функция арности 0 (количество аргументов = 0).
Аналог Supplier в java 8. Сокращенная запись () => T, но можно записать и как Function0[T] (не ясно, правда, зачем). https://scalafiddle.io/sf/qs25LOB/1:
def test1(f: () => String) = f()
def test2(f: Function0[String]) = f()

println(test1{ () => "Hi!" })
println(test2{ () => "Hi!" })
Вы мне отвечаете?

Зачем в java return понятно — там есть множество синтаксических конструкций, не являющихся выражениями. В первую очередь это if и try.

В этом отношении в scala return не нужен.

И тем более он не нужен внутри лямбды: лямбда должна состоять из небольшого количества выражений, в идеале однострочник. Если же требуется что-то большое — пишите метод (и для java 8 работает).
Чтоб не быть голословным: https://scalafiddle.io/sf/1PJR8IG/0

А return для тех, кто документацию не прочитал.
Выше я описал единственную адекватную причину использовать return после прочтения инструкции.
Либо удосужится прочитать документацию и узнать о find/collectFirst и ленивых коллекциях.
Кстати, это отлично иллюстрирует, что использовать объединения в качестве Validation нельзя. Метод getStoredError будет иметь тип Error | Error.
Иногда создавать ADT либо излишне, либо невозможно.

Излишне это бывает, например, в Validation, когда комбинируются ошибки из разных источников. Может оказаться, что каждый второй метод требует специального ADT под тип ошибки, да еще и мапить ошибки постоянно. С объединениями же можно написать так:
Validated[Error1 | Error2, Result].

В Dotty собираются ввести nullable типы следующим образом: T? становится синонимом для T | Null. Это тоже весьма удобно и не влечет потери в производительности.

Но как основную причину появления объединений в Dotty я слышал то, что в некоторых случаях при попытке свернуть тип выражения (например 2 веток if) компилятор упирался в бесконечные или просто невыразимые типы, так что объединения упростили компилятор и дизайн языка.
строго с такими же типами

Тут я все-таки опять не достаточно хороший пример привел. Тип результата не обязан совпадать с типом параметра. Совсем синтетический пример: https://scalafiddle.io/sf/apdsGEh/4.
Также есть zip на HList, возвращающий строго типизированный HList и многие другие методы.
Подобное требуется при метапрограммировании.
Спасибо, интересно.

22. Немножко громоздко, но можно привыкнуть. Я правильно понимаю, что вот для такого понадобятся дополнительные скобки?
val res = for {
 x <- 1 to 15 by 2
 z = x*x -1
 if z % 3 == 0
 y <- 1 to 10 by 3
} yield z -> y

Future же к коллекции не привести, или я не прав? Да и потеря типа не приятна.
Есть аналог async/await?
Там, на самом деле более сложный вопрос — как в for работать с Future[Validation[...]] — для асинхронной обработки результата. В scala для этого monad transformers.

24. Мне кажется больше проблем в десериализации generic типа — если экземпляр создан в java, то у него не будет метаинформации о конкретном типе с которым он создан. И ceylon код, рассчитывающий на эту информацию будет несколько удивлен.
На всякий случай, чтоб мы говорили об одном и том же.
Вот пример полиморфного метода: https://scalafiddle.io/sf/8Sq4LJv/0
(1, 3.14, "str") map increase
// (Int, Double, String) = (2,4.140000000000001,str + 1)
Жаль. Возможность возвращать разный тип результата в зависимости от типа аргумента в HList::map позволяет делать очень интересные вещи.
Например глубокое сравнение для case class:
Foo(2, "foo") delta Foo(8, "bar")
// 6 :: ("foo", "bar") :: HNil
Раз уж в статье идет сравнение со scala, я позволю себе развить эту тему:
18# Типы — объединения (union types)
В большинстве языков программирования функция может может возвратить значения строго одного типа.
Это если не учитывать наследование и ADT.
Для возвращения ошибок есть Validation
val p = Validated.catchNonFatal {
  Integer.parseInt("56")
}

Если же очень хочется именно объединения, то это потребует не намного больше кода:
type F = Boolean :+: Double :+: String :+: Null :+: List[Nothing] :+: CNil
def f(): F = {
  val rnd = util.Random.nextInt(5)
  rnd match {
    case 0 => Coproduct[F](false)
    case 1 => Coproduct[F](1.0)
    case 2 => Coproduct[F]("2")
    case 3 => Coproduct[F](null)
    case _ => Coproduct[F](List.empty)
  }
}

val v = f()

v.select[Double].foreach { d => println(s"Double $d") }
v.select[Int].foreach { i => println(s"Int $i") } // не скомпилируется, v не может быть Int

Кстати, в ceylon можно ли обработать весь тип объединения полиморфным методом с сохранением типов?
object headOption extends (List ~> Option) {
  def apply[T](l: List[T]) = l.headOption
}

val x = Coproduct[List[Int] :+: List[String] :+: CNil]("str" :: Nil)

val res: Option[Int] :+: Option[String] :+: CNil = x map headOption

res.select[Option[Int]].isEmpty
// true
res.select[Option[String]].nonEmpty
// true


19# Типы — пересечения (Intersection types)

Это не проблема тех пор, как придумали наследование:
trait CanRun {
    def run() = println("I am running")
}

trait CanSwim {
    def swim() = println("I am swimming")
}

trait CanFly {
    def fly() = println("I am flying")
}

case class Duck() extends CanRun with CanSwim with CanFly
case class Pigeon() extends CanRun with CanFly {}
case class Chicken() extends CanRun {}
case class Fish() extends CanSwim {}

def f(arg: CanFly with CanSwim) = {
    arg.fly(); 
    arg.swim();
}

f(Duck()); //OK Duck can swim and fly
f(Fish()); //ERROR = fish can swim only


20# Типы — перечисления (enumerated types)

Обычно это называется ADT (algebraic data type).
В scala тоже позволяет компилятору проверять полноту сопоставления с образцом.

23# Алиасы типов (Type aliases)
Или на класс, причем класс с конструктором:

Интересный синтаксис, но мне кажется удобнее сделать ссылку на весь компаньон, чтоб получить все методы:
type MyList[T] = List[T]
val MyList = List

val ml1: MyList[Int] = MyList.empty
val ml2: MyList[Int] = MyList("str")


21# Кортежи

Выше уже отметил, что лучшим аналогом в scala является HList.

22# Конструирование коллекций (for comprehensions)

Многомерное итерирование поддерживатеся?
val res = for {
 x <- 1 to 15 by 2
 if x % 3 == 0
 y <- 1 to 10 by 3
} yield x -> y
// Vector((3,1), (3,4), (3,7), (3,10), (9,1), (9,4), (9,7), (9,10), (15,1), (15,4), (15,7), (15,10))

Это только для коллекций или можно обобщить на произвольную монаду?

24# Улучшенные дженерики

Вообще хорошо, но нельзя забывать, что это влечет некоторые проблемы при взаимодействии с java. Например с java библиотеками для сериализации в JSON.

24# Метамодель

Звучит очень хорошо. Это полноценный механизм макросов как в scala? Можно при помощи него генерировать новые классы во время компиляции?

#25 Общий дизайн языка

Дискуссионный момент. Кому-то (например мне) может больше нравиться подход scala, где сделан упор на расширяемость языка, что позволяет делать такие сторонние библиотеки как shapeless, cats и другие, привносящие в язык новые концепции.
Судя по описанию, кортежи в ceylon ближе к HList, чем к Tuple.
В связи с чем вопрос: можно ли выполнить map по кортежу с сохранением информации о типах элементов?
Примерно так:
scala> (1, "str", 'sym) map elemToList
res1: (List[Int], List[String], List[Symbol]) = (List(1),List(str),List('sym))

Полный код по ссылке.
Это компромисс для плавного перехода с java. Если не ошибаюсь негативные его последствия были описаны еще в первой версии Programming in Scala.
Нужен он чтоб подобное работало:
for (i <- 0 to (array.length - 1)) {
  if (...) return array(i)
}

За пределами добра и зла это было когда в этом исключении был не отключен стектрейс. Теперь это не слишком дорого.

Не думайте, что на эти грабли наступают многие. Чтобы воспользоваться return в лямбде в scala для возвращения результата из этой лямбды надо обладать неординарным воображением.

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Дата рождения
Зарегистрирован
Активность