[Программирование, Scala] Scala как первый язык

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
21-Окт-2020 19:31


Лестница в логотипе отсылает к институту EPFL в Лозанне. Там придумали этот языкЭта статья, как имой предыдущий пост, не похожа на то, что обычно публикуют на Хабре.  Здесь не объясняется никаких новых или старых концепций, я не рассказываю что такое ООП и функциональное программирование, сложного кода почти нет. Я хочу пригласить вас к дискуссии стоит ли начинать программировать с языка Scala.
Время от времени ко мне обращаются знакомые с просьбой помочь в изучении программирования и посоветовать, с чего начать. Я хорошо понимаю трудности, которые ожидают разработчика на Scala, но тем не менее считаю, что она может оказаться удачным выбором. Я думаю, что будущее за такими языками. Что же мне так нравится в скале?
Это другая лестница by JuJu Lyn on Unsplash blog.softwaremill.com/annoying-things-in-scala-2-thatll-be-mostly-gone-in-scala-3-e1479a6d855cУмный компиляторУ скалы один из самых сложных компиляторов. Это приводит к очень медленным билдам (особенно в первых версиях языка), и за это скала-компилятор хейтят. Но это позволяет отдать компилятору очень много работы по анализу кода, проверке его на безопасность и отсутствие ошибок, что очень важно для программиста. Я люблю говорить, что джава — это язык, удобный для компилятора, а скала — это язык, удобный для программиста.JVM-экосистемаКак известно, Джеймс Гослинг, создатель языка джава, считает самой лучшей ее частью джава-машину. Действительно, много инженеров потратило десятки человеко-лет на разработку виртуальной машины и достигли скоростей, превышающих Си++. Кстати, Джеймсу Гослингу скала тоже нравится.Модель памяти для многопоточных вычислений JVM — это зрелая, непротиворечивая, проверенная многими годами промышленного программирования парадигма, которая при правильном использовании гарантирует достаточный уровень абстракции и безопасности. Кроме того, на джаве написаны миллионы строк кода, которые вы можете использовать из скалы или без проблем в нее транслировать.Но в этом всем есть и минусы. Как мы знаем, верхнеуровневые абстракции протекают, и для того чтобы программировать на скале, важно знать как устроена виртуальная машина джава, и учитывать ее особенности. Например, такие как Type Erasure.Обратная совместимостьВ экосистеме скалы приняты довольно слабые гарантии обратной совместимости по сравнению с джавой. С одной стороны, это приводит к тому, что разработчикам постоянно приходится поддерживать свой код в форме при переходе на новую версию языка или библиотек. Кроме того, разработчикам библиотек приходится прибегать к кросс-компиляции для того чтобы обеспечить несколько версий скомпилированных библиотек, подходящих для нескольких версий языка. Это, безусловно, минус.Но с другой стороны такой подход обеспечивает быстрое и динамичное развитие языка, которое не может себе позволить джава. Именно поэтому я думаю что будущее — за скалой. К тому же, вScala 3 появилось типизированное абстрактное синтаксическое дерево компилятора TASTY, которое позволит взаимодействовать классам, собранным разными версиями компилятора.Scala 3Благодаря более слабым гарантиям обратной совместимости, разработчики языка получили возможность пересмотреть его основы, включая синтаксис. Первоначальным посылом к созданию скалы было сделать язык промышленного уровня, на котором будет приятно программировать. Это действительно был большой шаг вперед и программисты на скале действительно занимают первые места в рейтингах любимых языков. Но некоторые решения, принятые более 15 лет назад, были неверными и приводили к неочевидному, либо многословному коду. И сейчас создатели языка делают его действительно лучше. После этих изменений шансы скалы в качестве первого языка программирования заметно вырастают.Я уже пару лет с нетерпением жду его выхода и мечтаю начать писать на нём. Вот сжатый рассказ Мартина Одерски про новую версию языка: Countdown to Scala 3 by Martin Odersky.DOTDependent Object Types — это теоретические основы языка Scala 3, разработанные его основателем Мартином Одерски. Мало какой язык может похвастать математически точным исчислением, лежащем в его основе.Выразительность и лаконичностьТо, что я больше всего люблю в языке — это его сжатость и лаконичность. Я ненавижу длиннейшие конструкции джавы, в которых приходится сложно и многословно объяснять компилятору простые вещи. Моя любимая шутка про джаву, что это такой язык, в котором уан-лайнер занимает около 30 строк. Так вон в скале уан-лайнер — это уан-лайнер.Я думаю, что это качество важно не только для опытных разработчиков, но и для тех кто только изучает язык, если оно не наносит ущерб читаемости кода.Понятно, что для написания библиотек важно понимать сложные концепции и знать много умных слов. Но для того, чтобы ими пользоваться и писать простой код, всего этого знать не надо. Минимальный уровень скалы, который подойдет начинающим, очень простой.Вот мой любимый пример для библиотечного кода на скале. Конечно, он не предназначен для начинающих разработчиков:
class Stack[+A] {
  def push[B >: A](elem: B): Stack[B] = new Stack[B] {
    override def top: B = elem
    override def pop: Stack[B] = Stack.this
    override def toString = s"$elem ${Stack.this}"
  }
  def top: A = sys.error("no element on stack")
  def pop: Stack[A] = sys.error("no element on stack")
  override def toString = ""
}
object VariancesTest extends App {
  println(Stack().push("hello").push(Object()).push(7))
}
Думаю, выразительность — это та причина, по которой так популярны динамические и скриптовые языки. Уверен, скала способна с ними в этом поспорить. И даже сама послужить отличным скриптовым языком. В новой версии языка даже есть возможность писать намного меньше фигурных скобок, а пользоваться отступами как в Питоне или в yaml-разметке.Это будет выглядеть примерно так:
enum IndentWidth:
  case Run(ch: Char, n: Int)
  case Conc(l: IndentWidth, r: Run)
  def <= (that: IndentWidth): Boolean = this match
    case Run(ch1, n1) =>
      that match
        case Run(ch2, n2) => n1 <= n2 && (ch1 == ch2 || n1 == 0)
        case Conc(l, r)   => this <= l
    case Conc(l1, r1) =>
      that match
        case Conc(l2, r2) => l1 == l2 && r1 <= r2
        case _            => false
  def < (that: IndentWidth): Boolean =
    this <= that && !(that <= this)
  override def toString: String = this match
    case Run(ch, n) =>
      val kind = ch match
        case ' '  => "space"
        case '\t' => "tab"
        case _    => s"'$ch'-character"
      val suffix = if n == 1 then "" else "s"
      s"$n $kind$suffix"
    case Conc(l, r) =>
      s"$l, $r"
object IndentWidth:
  private inline val MaxCached = 40
  private val spaces = IArray.tabulate(MaxCached + 1)(new Run(' ', _))
  private val tabs = IArray.tabulate(MaxCached + 1)(new Run('\t', _))
  def Run(ch: Char, n: Int): Run =
    if n <= MaxCached && ch == ' ' then
      spaces(n)
    else if n <= MaxCached && ch == '\t' then
      tabs(n)
    else
      new Run(ch, n)
  end Run
  val Zero = Run(' ', 0)
end IndentWidth
Статическая типизацияПо-моему это самое важное что должно быть в первом языке программирования. Программисту важно понимать, что не стоит складывать яблоки с апельсинами. Все в порядке с Питоном, Руби, Джаваскрипт, Си и Си++, на мой взгляд не стоит начинать обучение с них. Динамическая типизация — это очевидный способ выстрелить себе в ногу. Другое дело, что статическая типизация неудобна, неочевидна и требует дополнительного бойлер-плейта. Скала вполне успешно позволяет избавиться от него в простых программах.ООПОбъектно-ориентированное программирование — это самая популярная парадигма, без которой не обходиться не один современный язык программирования. В скале эта парадигма изначально присуща языку, в отличии от Питона, Си и в каком-то смысле джаваскрипта. Функциональное программированиеФункциональное программирование — это многообещающая тенденция. Скале она присуща в не меньшей степени чем ООП, и они взаимно обогащают друг друга благодаря этому языку. Рискну предположить, что скала — первый язык промышленного уровня с такими свойствами. Сейчас за ним подтягивается Котлин и другие более новые языки.Начинающим разработчикам стоит узнать про функциональное программирование подробнее, этот подход позволяет писать гибкий, надежный и хорошо масштабируемый код. Вот несколько хабропостов о нём: ИммутабельностьВообще-то это свойство функционального программирования. Мне кажется очень важным прививать умение пользоваться иммутабельными структурами данных с самого начала. Это позволит в будущем создавать безопасный многопоточный код. И не только многопоточный.Расширяемость Как известно, название языка изначально преподносилось как аббревиатура Scalable Language. Особенности языка позволяют писать гибкие и красивые DSL, вкладывать абстракции друг в друга, создавать очень удобные библиотеки и простые скрипты. Это был последнее свойство языка, которое мне хотелось бы обсудить. Некоторые свойства отображены на картинке ниже.Свойства языка Scala
Источник: https://prwatech.in/blog/apache-spark/introduction-...amming-language/Рынок вакансийКонечно, вакансий для скала-программистов значительно меньше, чем для джава-программистов. Но тем не менее язык демонстрирует стабильный рост и превосходит все остальные java-based языки, не считая самой джавы. Ближе всего из JVM-языков к нему подбирается Котлин благодаря тому, что его используют для программирования под мобильные телефоны. Сама джава по-прежнему вне конкуренции и больше всего JVM-вакансий именно на ней. Вот вам картинка про области применения скалы.
Источник: https://prwatech.in/blog/apache-spark/introduction-...amming-language/Мои первые книжкиСамая лучшая книжка про скалу, которую я читал —Scala by Example Мартина Одерски, написанная уже 10 лет назад. С тех пор книжек по скале я не читал.А любимый курс — это Functional Programming in Scala, я проходил его в самой первой версии, с тех пор он, конечно, успел измениться.Если вы хотите поиграться скалой, не устанавливая IDE — добро пожаловать в Scastie.Поступь прогрессаШутка Кея Хорстмана «The March of Progress»1980: C 
printf("%10.2f", x);
1988: C++
cout << setw(10) << setprecision(2) << fixed << x;
1996: Java
java.text.NumberFormat formatter = java.text.NumberFormat.getNumberInstance();
formatter.setMinimumFractionDigits(2);
formatter.setMaximumFractionDigits(2);
String s = formatter.format(x);
for (int i = s.length(); i < 10; i++) System.out.print(' ');
System.out.print(s);
2004: Java
System.out.printf("%10.2f", x);
2008: Scala and Groovy
printf("%10.2f", x)
2012: Scala 2.10
println(f"$x%10.2f")
Пример лаконичного кодаВот самый популярный пример лаконичности скалы по сравнению с джавой.Scala
case class Person(firstName: String, lastName: String)
val mr = Person("Bob", "Dobbelina")
val miss = Person("Roberta", "MacSweeney")
val mrs = miss.copy(lastName = mr.lastName)
Java
public class Person implements Serializable {
    private final String firstName;
    private final String lastName;
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public Person withFirstName(String firstName) {
        return new Person(firstName, lastName);
    }
    public Person withLastName(String lastName) {
        return new Person(firstName, lastName);
    }
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Person person = (Person) o;
        if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
            return false;
        }
        if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
            return false;
        }
        return true;
    }
    public int hashCode() {
        int result = firstName != null ? firstName.hashCode() : 0;
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        return result;
    }
    public String toString() {
        return "Person(" + firstName + "," + lastName + ")";
    }
}
Person mr = new Person("Bob", "Dobbelina");
Person miss = new Person("Roberta", "MacSweeney");
Person mrs = miss.withLastName(mr.getLastName());
Еще примерScala
object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}
Java 8
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer");
    Map<Character, List<String>> result = keywords.stream().sorted().collect(Collectors.groupingBy(it -> it.charAt(0)));
    System.out.println(result);
  }
}
Java 7
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer");
    Map<Character, List<String>> result = new HashMap<Character, List<String>>();
    for(String k : keywords) {
      char firstChar = k.charAt(0);
      if(!result.containsKey(firstChar)) {
        result.put(firstChar, new  ArrayList<String>());
      }
      result.get(firstChar).add(k);
    }
    for(List<String> list : result.values()) {
      Collections.sort(list);
    }
    System.out.println(result);
  }
}
Мой первый промышленный код на скалеВот вам на прощанье фрагмент моего первого в жизни скрипта на языке скала:
import scala.sys.process._
import scala.io.Source
import scala.collection.JavaConversions._
import java.nio.charset.Charset
import java.nio.file._
import scala.collection.mutable.ArrayBuffer
import java.nio.file.attribute.BasicFileAttributes
  val pretend = true // set to false to run in real mode
  val commit = "765163c6cb31c9df1ad3dc86c6ca6053cf25deeb"
  val srcDir = Paths.get("C:/Dev/source/ant-project")
  val destDir = Paths.get("C:/Dev/source/mvn-project")
  val workDir = Paths.get("work")
  val nameFile = workDir.resolve("gitlog.txt")
  val changesetFile = workDir.resolve("changeset.txt")
  val unwiseCommandFile = workDir.resolve("unwise.cmd")
  val wisesetFile = workDir.resolve("wiseset.txt")
  val wiseCommandFile = workDir.resolve("wise.cmd")
  val pretendOp = if (pretend) "-n " else ""
/**
  * Script to prepare modified files, placing them to the old place,
  * To be run before the merge
  */
  def unwiseChanges = {
    Files.createDirectories(workDir)
    val logcmd =
      s"""git log $commit..HEAD --pretty="format:" --name-only"""
    val exitVal = Process(logcmd, srcDir.toFile) #> nameFile.toFile !
    if (exitVal != 0) exit(exitVal)
    val lines = Source
      .fromFile(nameFile.toFile)
      .getLines
      .filter(!_.isEmpty)
    val files = lines
      .map(Paths.get(_))
      .toList
      .sorted
      .distinct
    val changeset = files.map { src =>
      src -> target(src)
    }
    Files.write(
      changesetFile,
      changeset.map(p => s"${p._1} -> ${p._2}"),
      Charset.defaultCharset
    )
    val adds = changeset
      .filter(p => Files.exists(srcDir.resolve(p._1))
              && Files.notExists(destDir.resolve(p._2)))
    val moves = changeset
      .filter(p => p._1 != p._2 && Files.exists(srcDir.resolve(p._1))
              && Files.exists(destDir.resolve(p._2)))
    val dels = changeset
      .filter(p => p._1 != p._2
              && Files.notExists(srcDir.resolve(p._1))
              && Files.exists(destDir.resolve(p._2)))
    val cmds =
      moves.map(p => s"""git mv -v ${pretendOp}"${p._2}" "${p._1}"""") ++
      dels.map(p => s"""git rm ${pretendOp}"${p._2}"""")
    println(adds.map(p => s"# add: ${p._1} -> ${p._2}").mkString("\n"))
    moves.foreach { p =>
      Files.createDirectories(destDir.resolve(p._1.getParent))
    }
    Files.write(unwiseCommandFile, cmds, Charset.defaultCharset)
    val results = cmds.map { cmd =>
      Process(cmd, destDir.toFile)!
    }
    println(s"""Successfully processed ${results.count(0 == _)} files,
               | failed: ${results.count(0 != _)} files""".stripMargin)
  }
  unwiseChanges
На этом я рискну опубликовать этот пост, но по-прежнему планирую его дописывать по результатам обсуждения с вами.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_scala, #_izuchenie_programmirovanija (изучение программирования), #_tutorial, #_programmirovanie (
Программирование
)
, #_scala
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 23-Ноя 01:06
Часовой пояс: UTC + 5