Scala (програмски језик)


Scala (изговор: Скала) је програмски језик за опште софтверске апликације. Скала има пуну подршку за функционално програмирање и веома јак систем статичких типова. Ово омогућава програмима написаним у Скали да буду веома концизни и тиме мањих димензија од осталих програмских језика опште намене . Многе одлуке при дизајну Скале биле су инспирисане критикама недостатака Јаве .[5]

Scala
ПарадигмаМулти-парадигма:
функционална, објективно-
оријентисана
, императивна,
конкурентна
Првобитни
програмер(и)
Мартин Одерски
Прва верзија20. јануар, 2004;
пре 11 година
Најновија
верзија
2.11.7 / 23. јун,
2015 пре 4
месеца[1]
Дисциплина куцањадинамична,снажна,
закључна, структурална
ПлатформаЈВМ, ЛЛВМ,
Јаваскрипт[2]
Лиценца3-условна
BSD лиценца
[3]
Екстензије.scala
Веб-сајтwww.scala-lang.org
Под утицајем
Common Lisp, Erlang, Haskell, ML, Prolog, Scheme, Java, Ruby[4]
Утицао на
Elixir, Pixie, Rhine

Предвиђено је да се изворни код Скале компајлира у Јава бајт код, тако да резултирајући извршни код ради на Јава виртуелној машини. Јава библиотеке могу да се користе директно у Скала коду и обрнуто (интероперабилност језика).[6] Као и Јава, Скала је објектно-оријентисана, и користи синтаксу која подсећа на C (програмски језик). За разлику од Јаве, Скала има много карактеристика функционалних програмских језика као што су Scheme, Стандард МЛ и Хаскел, укључујући кјуринг, подразумеване типове података, непроменљивости, лење евалуације, и патерн мечинг. Такође има напредни систем типова података који подржава алгебарски тип података, коваријансу и нековаријансу, типове вишег реда (али не и типове вишег ранга), и анонимне типове. Остале карактеристике Скале не постоје у Јави, укључујући преклапање оператора, факултативне параметре, назване параметре, сирове стрингове, и непроверене изузетке.

Име Скала је кованица од "скалабилности" и "језика", што значи да је дизајнирана да расте са захтевима својих корисника.[7]

Историја

уреди

Нацрт Скале је почео 2001. године на Екол Политекник Федерал де Лозан (ЕПФЛ) Мартин Одерски, који се надовезао на рад на Фунелу, програмском језику који комбинује идеје функционалног програмирања и Петри мрежа.[8] Одерски је раније радио на Џенерик Јави и јавцу, Сан Јави преводиоцу.[8]

Након интерног пуштања крајем 2003. године, Скала је јавно објављена почетком 2004. године на Јава платформи,[9] и на . НЕТ платформи јуна 2004. године.[5][8][10] Друга верзија (в2.0) испраћена је марта 2006. године.[5] Подршка за . НЕТ је званично напуштена 2012. године.[11]

Иако је Скала имала широку подршку за функционално програмирање од почетка, Јава остаје чисто објектно-оријентисани језик до увођења ламбда израза са Јавом 8 2014. године.

Дана 17. јануара 2011. године тим Скале је освојио донацију од преко 2,3 милиона € за петогодишње истраживање од Европског савета за истраживање.[12] 12. маја 2011. године, Одерски и сарадници су покренули Тајпсејф Инц., компанију за пружање комерцијалне подршке, обуке и услуга за Скалу. Тајпсејф је добио инвестицију вредну 3 милиона долара 2011. године од Грејлок Партнера.[13][14][15][16]

Платформе и лиценце

уреди

Скала ради на Јава платформи (Јава виртуелној машини) и компатибилна је са постојећим Јава програмима.[9]  Како се Андроид апликације углавном достављају као Јава бајт код, Скала је погодна за њихов развој.[17] Скала се може компилирати у ЈаваСкрипт, тако да је могуће написати Скала програме који могу да раде у претраживачу.[18]

Софтвер дистрибуције Скале, укључујући преводилац и библиотеке, је објављен под BSD лиценцом.[19]

Примери

уреди

Пример "Здраво, свете"

уреди
 object HelloWorld extends App {
   println("Hello, World!")
 }

За разлику од самосталне Здраво свете апликације за Јава, овде нема класе декларације и ништа се проглашава статичним; уникод креиран са објектом кључне речи се користи.

Са програмом сачуваним у фајл по имену ЗдравоСвете.scala, могуће је саставити из командне линије:

$ scalac ЗдравоСвете.scala

Да би га стигао:

$ scala ЗдравоСвете (Мора се користити "-cp" кључ комплета класнопутног као у Јави).

Ово је аналогно процесу прикупљање и рада Јава кода. Заиста, Скала је компилација и извршење модела идентичном оном из Јаве, што га чини компатибилним са Јава направом алат, као што је Ант.

Краћа верзија "Здраво свете" Скале програма је:

println("Hello, World!")

Скала укључује интерактивну шкољку и нацрт  подршке.[20] Сачувано као фајл под називом ЗдравоСвете2.scala, може да покрене као скрипту без претходне компилације користећи:

$ scala ЗдравоСвете2.scala

Команде могу бити унете директно у Скала интерпретатор, коришћењем опције -e:

$ scala -e 'println("Здраво, свете!")'

Најзад, команда може бити унета интерактивно са REPL:

$ scala
Welcome to Scala version 2.10.3 (OpenJDK 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.

scala> println("Здраво, свете!")

Здраво, свете!

scala> 

Основни пример

уреди

Следећи пример показује разлику између записа у Јави и Скали:

// Java:
int mathFunction(int num) {
    int numSquare = num*num;
    return (int) (Math.cbrt(numSquare) +
      Math.log(numSquare));
}
// Scala: Direct conversion from Java

// no import needed; scala.math
// already imported as `math`
def mathFunction(num: Int): Int = {
  var numSquare: Int = num*num
  return (math.cbrt(numSquare) + math.log(numSquare)).
    asInstanceOf[Int]
}
|
// Scala: More idiomatic
// Uses type inference, omits `return` statement,
// uses `toInt` method, declares numSquare immutable

import math._
def intRoot23(num: Int) = {
  val numSquare = num*num
  (cbrt(numSquare) + log(numSquare)).toInt
}

Неке синтаксне разлике у овом коду су:

  • Скала не захтева запету на крају изјаве.
  • Типови вредности су капитализовани: Int, Double, Boolean уместо int, double, boolean.
  • Параметар и повратак врсте следе, као и у Паскалу, или претходе као у Ц.
  • Методама мора претходити def.
  • Локалним или класама променљиве мора претходити val (указује непроменљиву променљиву) или var (указује променљиву променљиву).
  • Оператор return је неопходан у функцији (иако дозвољено);вредност последњег извршеног кода или израза је нормално вредност ове функције.
  • Уместо Јава оператора (Type) foo, Скала користи foo.asInstanceOf[Type], или специјалне функције као што су toDouble или toInt.
  • Уместо у Јави import foo.*;, Скала користиimport foo._.
  • Функције или метода foo() може се назвати сад foo; метода thread.send(signo) може се назвати сад thread send signo; и метода foo.toString() може се назвати foo toString.

Неке друге основне синтаксичке разлике:

  • Референце реда су написане као позиви функција, нпр array(i) док је array[i]. (интерно у Скали, оба низа и функције концептуализоване су као врсте математичких мапирања из једног објекта на други.)
  • Опште врсте се пишу као нпр List[String] док у Јави  List<String>.
  • Уместо псеудо-типа void, Скала садржи актуелни уникод  Unit (види испод).

Примери са класама

уреди

Следећи пример садржи дефиницију класа у Јави и Скали.

// Java:
public class Point {
  private final double x, y;

  public Point(final double x, final double y) {
    this.x = x;
    this.y = y;
  }

  public Point(
    final double x, final double y,
    final boolean addToGrid
  ) {
    this(x, y);
  
    if (addToGrid)
      grid.add(this);
  }

  public Point() {
    this(0.0, 0.0);
  }

  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }

  double distanceToPoint(final Point other) {
    return distanceBetweenPoints(x, y,
      other.x, other.y);
  }

  private static Grid grid = new Grid();

  static double distanceBetweenPoints(
      final double x1, final double y1,
      final double x2, final double y2
  ) {
    return Math.hypot(x1 - x2, y1 - y2);
  }
}
|
// Scala
class Point(
    val x: Double, val y: Double,
    addToGrid: Boolean = false
) {
  import Point._

  if (addToGrid)
    grid.add(this)

  def this() = this(0.0, 0.0)

  def distanceToPoint(other: Point) =
    distanceBetweenPoints(x, y, other.x, other.y)
}

object Point {
  private val grid = new Grid()

  def distanceBetweenPoints(x1: Double, y1: Double,
      x2: Double, y2: Double) = {
    math.hypot(x1 - x2, y1 - y2)
  }
}

Наведени код показује неке од концептуалних разлика између Јаве и Скале класе:

  • Скала нема статичке променљиве или методе. Уместо тога, она има синглетон објекте, који су у суштини класе са само једним објектом у разреду. Синглетон објекти су проглашени коришћењем object уместо  class. Уобичајно је да се ставе статичке променљиве и методе у синглтон објекту са истим именом као и именом класе, која је тада позната као пратилац објекта.[9] (Основна класа за синглетон објекат има $ у прилогу. Дакле, за class Foo са пратиоцем објекта object Foo, испод хаубе има класа Foo$ која садржи код пратилац објекта, и један објекат ове класе је креиран, користећи уникод.)
  • Уместо конструктора параметара, Скала има параметре класе, који се налазе на самим класама, сличним параметрима на функцији. Када је проглашена са val или  var модификатор, поља су такође дефинисани са истим именом, и аутоматски се иницијализују од параметара класе. (Под хаубом, спољашњи приступ јавним областима увек пролази кроз пријемник (гетер) и мутатор (сетер) методе, које је аутоматски креирао. Пријемник функције има исто име као на терену, због чега је непотребно у горњем примеру до експлицитно изјасни пријемник методе.) Пазити да алтернативни конструктори ће такође бити проглашени, као у Јави. Код који ће ићи у подразумевани конструктор (осим инитициализоване променљиве мембер) иде директно на ниво класе.
  • Уобичајна видљивост у Скали је public.

Карактеристике (са освртом на Јаву)

уреди

Скала има исту компилацију модела као Јава и C#, односно посебне компилације и динамичне класе оптерећења, тако да код Скале може да позове Јава библиотеке, или .нет библиотеке у имплементацији . НЕТ.

Оперативни карактеристике Скале су исте као Јаве. Скала преводилац генерише бајт код који је готово идентичан ономе који генерише Јава преводилац.[9] У ствари, Скала код може бити неразумна за читање Јава кода, са изузетком неких конструктора операција. За ЈВМ, Скала код и Јава код се могу разликовати. Једина разлика је једноставан екстра рантајм образац, scala-library.jar.[21]

Скала додаје велики број функција у поређењу са Јавом, и има неке фундаменталне разлике у свом основном моделу израза и врста, које чине теоретски језик чистијми и елиминишу велики број "корнер случаја" у Јави. Из перспективе Скале, ово је практично важно јер велики број додатних карактеристика у Скала је такође доступан у C#. Примери укључују:

Синтаксну флексибилност

уреди

Као што је већ поменуто, Скала има доста синтаксних флексибилности, у поређењу са Јавом. Следе неки примери:

  • Зарепете су непотребне; линије аутоматски почињу или се заврше знаком који не може нормално доћи у тај положај, или ако постоје незатворене заграде или заграде.
  • Било који поступак се може користити као оператор поправке, нпр "%d apples".format(num) и  "%d apples" format num су еквивалентни. Заправо, аритметичке операције попут  + и << се третирају као било које друге методе, јер имена функција могу да се састоје од секвенце произвољних симбола (са неколико изузетака направљених за ствари као што су паренс, заграде и протезе које се морају посебно здружити); само посебним третманом такви симболи назива метода прођу бриге руковања приоритета.
  • Методе apply и update имају синтаксно кратке форме. foo()—где foo је вредност (синглетон објекат или инстанца класе)—је кратак за foo.apply(), и foo() = 42 кратак је за foo.update(42). Слично, foo(42) је кратко за foo.apply(42), и foo(4) = 2 је кратко за foo.update(4, 2). Ово се користи за класе прикупљања и простире се на многим другим случајевима, као што су СТМ ћелије.
  • Скала прави разлику између не-паренс (def foo = 42) и празног паренс (def foo() = 42) метода. Када се позива празна-паренс метода, заграде могу бити изостављене, што је корисно приликом позивања Јава библиотека које не знају ту разлику, на пример, користећи foo.toString уместо  foo.toString(). По конвенцији, метод треба дефинисати са празним-паренсом када он обавља  последице.
  • Метод имена завршава се двема тачака (:) очекивањем аргумента на левој страни и пријемника на десној страни. На пример, 4 :: 2 :: Nil је исто као Nil.::(2).::(4), први облик одговара визуелно резултату (листа са првог елемента 4 и другог елемента 2).
  • Класа тела променљивих се може транспарентно спроводити посебним гетер и сетер методама. За trait FooLike { var bar: Int }, имплементација може бити object Foo extends FooLike { private var x = 0; def bar = x; def bar_=(value: Int) { x = value }} } }. Позив сајт ће и даље моћи да користи концизан foo.bar = 42.
  • Коришћење великих заграда уместо заграда је дозвољено у позиву метода. Ово омогућава чисте имплементације библиотека нових контролних структура.[22] На пример, breakable { ... if (...) break() ... } изгледа исто ако breakable је кључна реч језика дефинисана, али на метода узимања мисли се на аргумент. Методе које узимају истину или функције и често их стављају листу другог параметра, дозвољавајући да се мешају заграде и заграде синтаксе: Vector.fill(4) { math.random } је исто као и Vector.fill(4)(math.random). Протезу коврџавих варијанти омогућава израз спана виших линија.
  • За изразе (објашњено доле) може да прими било какву врсту која дефинише методе као што су map, flatMap и filter.

Сами по себи, они могу изгледати као спорни избори, али колективно служе као сврха дозвољавања домена специфичних језика дефинисаних у Скали без потребе да се продужи преводилац. На пример, Ерлангова специјална синтакса за слање, односно. actor ! message може бити (и јесте) спровођење у Скали библиотеке без потребе језичких додатака.

Обједињени типови система

уреди

Јава прави оштру разлику између примитивног типа (нпр int и boolean) и референтних врста (било класа). Само референтне врсте су део шеме наслеђивања, која произилази из java.lang.Object. У Скала, међутим, све врсте су наслеђене од класе на највишем нивоу Any, чија су деца непосредно AnyVal (вредносни типови, попут Int и Boolean) и AnyRef (референтни типови, као у Јави). То значи да Јава разлика између примитивних типова и кутија врсте (нпр. int против  Integer) није присутна у Скали; кутија и некутија је потпуно транспарентна за корисника. Скала 2.10 дозвољава нове врсте вредности које су дефинисане од стране корисника.

За-изрази

уреди

Уместо Јава петље "форич" преко итератора, Скала има много снажнији концепт for-израза. Ово је слично листи схватања у језицима као што су Хаскел, или комбинацијом листе схватања и генератора израза у Пајтону. За-изразе, користећи при томе yield кључна реч омогућава нову колекцију која се генерише итеративно преко постојећег, и враћа нову колекцију истог типа. Они су преведени од стране преводиоца у низу map, flatMap и filter позива. Где yield није коришћен, код приближних петљи, превођењем на foreach.

Прости пример је:

val s = for (x <- 1 to 25 if x*x > 50) yield 2*x
val s = for (x <- 1 to 25 if x*x > 50) yield 2*x

Резултат је следећи вектор:

Vector(16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50)

(Пазити да израз 1 to 25 није специјална синтакса. Метода to је прилично дефинисано у стандарду библиотеке Скала као поступак екстензије на целе бројева, употребом технике познате као имплицитне конверзије[23] који омогућава нове методе додавањем постојећих типова.)

Сложенија пример итератинга преко мапе:

// Given a map specifying Twitter users mentioned in a set of tweets,
// and number of times each user was mentioned, look up the users
// in a map of known politicians, and return a new map giving only the
// Democratic politicians (as objects, rather than strings).

val dem_mentions = for {
    (mention, times) <- mentions
    account          <- accounts.get(mention)
    if account.party == "Democratic"
  } yield (account, times)

Израз (mention, times) <- mentions је пример патерн метинг (види доле). Итератинг преко мапе враћа скуп кључних вредности торки, и образац-подударања лако омогућава да торке буду у одвојеним варијаблама за кључ и вредност. Слично томе, резултат схватања и враћања кључа-вредности записа, који је аутоматски уграђен назад у мапи, јер извор објекта (из променљиве mentions) је мапа. Пазити ако је mentions уместо одржаног листа, комплет, низ или други збир торки, потпуно исти код изнад би дао нову колекцију истог типа.

Функционалне тенденције

уреди

Иако подржава све објектно-оријентисане расположиве могућности у Јави (и, у ствари, повећавајући их на разне начине), Сцала такође пружа велики број могућности које су на обично налазе само у функционалним програмским језицима. Заједно, ови особине омогућавају Скала програми који се уписују у готово потпуно функционалне стила, а такође омогућити функционалне и објектно оријентисани стилова да се мешају.

Примери су:

Све је у изразу

уреди

За разлику од C или Јава, или слична језицима као што су Lisp, Скала не прави разлику између изјава и израза . Све изјаве су у ствари изрази који оцењују неке вредности. Функције које би се изјасниле као повратак  void у C или Јави, изрази су попут while да логички не врати вредност, у Скали се сматра врати тип Unit, што је уникод, са само једним објектом тог типа. Функције и оператори које никада не врати (нпр throw оператер или функција која увек излази не-локално користећи изузетак) , логично има повратни тип  Nothing, посебна врста не садржи никакве предмете;то јес, дно типа, односно сваку подкласу могућег типа. (Ово заузврат чини тип Nothing компатибилан са свим типовима , омогућавајући тип закључак да функционише исправно . ) 

Слично,  if-then-else "изјава" је заправо израз, који производи вредност, односно резултат процене једног од два крака. То значи да такав блок кода се може уметнути где год се жели израз, избегавајући потребу тернарног оператера у Скали : 

// Java:
int hexDigit = x >= 10 ? x + 'A' - 10 : x + '0';
|
// Scala:
val hexDigit = if (x >= 10) x + 'A' - 10 else x + '0'

Из сличних разлога, return изјаве нису потребне у Скали, а у ствари су обесхрабрене. Као и у Lisp-у, последњи израз у блоку кода је вредност тог блока кода, а ако је блок кода тело функције, она ће бити враћена функцијом. 

def printValue(x: String): Unit = {
  println("I ate a %s".format(x))
}

или еквивалентно (са типом закључак, и изостављање непотребне заграде) :

def printValue(x: String) = println("I ate a %s" format x)

Тип закључак

уреди

Због типа закључка, врсте променљивих, вредности функција повратка, и многи други изрази се обично могу изоставити, јер компајлер може закључити. Примери су  val x = "foo" (за непроменљиве, константне променљиве или непроменљиве предмете) или  var x = 1.5 (за променљиве чија вредност се касније може мењати).

def formatApples(x: Int) = "I ate %d apples".format(x)

или (са повратним типом за рекурзивну функцију)

def factorial(x: Int): Int =
  if (x == 0)
    1
  else
    x*factorial(x - 1)

Анонимне фунције

уреди

У Скали, функције су објекти, а погодна синтакса постоји за одређивање анонимних функција. Пример је израз  x => x < 2, који одређује функцију са једним параметром, који пореди свој аргумент да види да ли је мање од 2. То је еквивалентно Lisp облику  (lambda (x) (< x 2)). Пазити да ни тип  x нити повратни ти изричит, а може генерално закључити по типу извођења, али се може експлицитно навести, нпр као  (x: Int) => x < 2 или (x: Int) => (x < 2): Boolean.

Чак краћи облик анонимне функције користи чуваре места променљиве: на пример, следеће : 

list map { x => sqrt(x) }

може бити написана и

list map { sqrt(_) }

или

list map sqrt

Постојаност

уреди

Скала спроводи разлику између непроменљивих варијабли, чија вредност не може бити промењена након доделе, и променљивих варијабли, које се могу мењати . Слична је разлика између непроменљивих и променљивих објеката. Разлика мора постојати када се прогласи променљива: непроменљиве променљиве су декларисане  val док променљиве варијабле користе var. Слично томе, сви објекти за сакупљање (врсте контејнера) у Скали, нпр. повезане листе, низови, сетови и хеш табеле, доступни су променљивим и непроменљивим варијантама, са непроменљивом варијантом сматра се више основна и подразумевана имплементација. Непроменљиве варијанте су "упорни" типови података праве нови објекат који обухвата стари објекат и додаје нови члана (С); ово је сличан начин повезане листе изграђене у Lisp-у, где су елементи препендедени стварањем нове "против" ћелије са показивачем новог елемента ("глава ") и старе листе ("реп"). Ово омогућава веома лаку конкуренцију - нема потребне браве какоо нема ни заједничких објеката икада модификовани. Непроменљиве структуре су такође изграђене ефикасно, у смислу да модификованом случајева реусес већина старих података степена и неискоришћених делова / унреференцед се прикупљају од ГЦ .[24]

Лење (нестроге) евалуације

уреди

Евалуација је строга ("нестрпљиви"). Другим речима, Скала оцењује изразе чим су доступни, него по потреби. Међутим, можете прогласи променљиву нестрогом ( "лењом" ) са  lazy кључном речју, што значи да код произведи вредност променљиве и неће бити вреднована до првог пута када се помене променљива. Нестрога складиштења разних врста такође постоје (као што су врста  Stream, нестрога повезана листа), и свака колекција постаје нестрога view методом. Нестроге колекције пружају добар семантички спрег ствари као што су сервер података, где је процена кода за генерисање касније елемената листе (која заузврат изазива захтев сервера, можда се налази негде другде на интернету) само се дешава када ствари потребе елементе.

Репна рекурзија

уреди

Функционални програмски језици обично пружају оптимизацију реп позива како би се омогућило широко коришћење рекурзије без стек оверфлоу проблема. Ограничења у Јава бајт кодовима компликују оптимизацију реп позива на ЈВМ. У принципу, функција која себе позива реп позивом може бити оптимизована, али међусобно рекурзивне функције не могу. Трамполине су предложене као алтернативно решење .[25] Подршка трамполине је показана од Скала библиотеке са објектом  scala.util.control.TailCalls од Скала 2.8.0 (обновљена 14. јула 2010. године).[26]

Случај класе и образац подударања

уреди

Скала има уграђену подршку за образац подударања, који се може посматрати као софистициранија, проширена верзије изјаве свич, где се могу поклопити произвољне врсте података (а не само једноставне врсте, као што су целих бројева, логички и стрингови), укључујући и произвољна угнежђења. Посебна врста класе позната као случај класе је обезбеђена, чиме укључује аутоматску подршку за образац подударања и може се користити за моделирање алгебарских типова података који се користе у многим функционалним програмским језицима.(Из перспективе Скале, случај класа је једноставно нормална класа за које преводилац аутоматски додаје одређена понашања која би могла бити обезбеђена мануелно нпр дефиниције метода које пружају дубока поређења и хеширање, и деструктурирање је предмет класе на својим конструкторима параметара током обрасца подударања). 

Пример дефиниције квиксорт алгоритма помоћу обрасца подударања гласи : 

def qsort(list: List[Int]): List[Int] = list match {
  case Nil => Nil
  case pivot :: tail =>
    val (smaller, rest) = tail.partition(_ < pivot)
    qsort(smaller) ::: pivot :: qsort(rest)
}

Идеја је да поделимо у листи елемената мање од стожера и елементе не мање, рекурсивним сортирањем сваког дела, и налепимо резултате заједно са стожером између. Ово користи иста стратегија подели па владај, мергсорта и других алгоритама за брзо сортирање.

Оператор match се користи да уради подударања узорака на објекту који се налази у list. Сваки case израз је покушао опет да види да ли ће се подударати, а први удар одређује резултат. У овом случају, Nil одговара само дословно објекат Nil, али pivot :: tail одговара непразној листи, и истовремено опадајућој листу према датом обрасцу. У том случају, повезан код ће имати приступ локалној променљивој по имену pivot државши главу на листи, и друге варијабле tail држаћи реп на листи. Имајте на уму да су ове варијабле само за читање, и да су семантички веома сличне променљивим утврђеним низовима користећи let оператор у Lisp-у и Шеми.

Образац подударање такође се дешава у локалним декларацијама променљивих. У том случају, повратак вредности позива се tail.partition је торка - у овом случају, две листе. (Торке се разликују од других врста амбалажа, нпр листа, у који су увек фиксне величине и елементи могу бити различитих типова. - Иако овде су оба исти) узорак подударања је најлакши начин да налажење два дела торке.

Форма _ < pivot је декларација анонимне функције са чуварем места променљиве; види део о анонимним функцијама.

Листа оператора :: (што додаје елемент на почетку листе, слично cons у Lisp-у и Шеми) и ::: (који додаје две листе заједно, слично је append у Lisp-у и Шеми), обоје нестају. Упркос наступима, не постоји ништа "уграђено" у вези било којих од ових оператера. Као што је пре спецификовано, сваки низ симбола може послужити као име функције, а метод се примењује на објекат који може бити написан "инфикс" стилом без периода или заграда. Линија изнад како је написано:

qsort(smaller) ::: pivot :: qsort(rest)

може бити записана и :

qsort(rest).::(pivot).:::(qsort(smaller))

у више стандардних метода позива запис.(Методе које се завршавају са двотачком у праву асоцијативе и везују се за објекат са десне стране.)

Парцијалне функције

уреди

У обрасцу разбијања горе наведеног примера, тело match оператора је парцијална функција, која се састоји од низа case израза, са првим одговарајућим преовладавајућим низом, слично телу изјаве. Парцијалне функције су такође користе у делу руковања са изузецима  try изјава:

try {
  ...

} catch {
  case nfe:NumberFormatException => { println(nfe); List(0) }
  case _ => Nil
}

Коначно, парцијална функција се може користити само од себе, а резултат назвавши еквивалентан је раду match . На пример, претходни код за брзо сортирање може се записати следећим:

val qsort: List[Int] => List[Int] = {
  case Nil => Nil
  case pivot :: tail =>
    val (smaller, rest) = tail.partition(_ < pivot)
    qsort(smaller) ::: pivot :: qsort(rest)
}

Само за читање променљивих је проглашен тип чија је функција листа целих бројева на листи целих бројева, и везују се парцијалном функцијом. (Имајте на уму да један параметар парцијалне функције се никада није изјавио.) Међутим, још увек можемо назвати ову променљиву баш као да је у питању нормална функција:

scala> qsort(List(6,2,5,9))
res32: List[Int] = List(2, 5, 6, 9)

Објективно-оријентисани изрази

уреди

Скала је чисто објектно-оријентисани језик у смислу да је свака Објекат. Типови података и понашања објеката су описани по врстама и особинама. Апстракције класа се продужавају подкласама и флексибилним механизмом измешане композиције засноване да би се избегли проблеми вишеструког наслеђивања.

Особине замене Скале је Јава интерфејс. Интерфејс верзија Јаве до 8 су веома ограничени, могли су само да садрже апстрактне декларације функција. То је довело до критика да пружање олакшају методе интерфејса непријатно (исте методе морају бити исте у сваком спровођењу), а проширење је објављен интерфејс уназад компатибилан начин је немогућ. Особине су слични миксин класама у томе што имају скоро сву моћ редовне апстрактне класе, у недостатку само параметре класе (Скала је еквивалентно градитељ Јава параметара), јер особине су увек помешане са класама. Оператор super се понаша посебно у особинама, омогућавајући особинама да се ланцима коришћењем композиција поред наследства. Следећи пример је једноставан прозорни систем:

abstract class Window {
  // abstract
  def draw()
}

class SimpleWindow extends Window {
  def draw() {
    println("in SimpleWindow")
    // draw a basic window
  }
}

trait WindowDecoration extends Window { }

trait HorizontalScrollbarDecoration extends WindowDecoration {
  // "abstract override" is needed here in order for "super()" to work because the parent
  // function is abstract. If it were concrete, regular "override" would be enough.
  abstract override def draw() {
    println("in HorizontalScrollbarDecoration")
    super.draw()
    // now draw a horizontal scrollbar
  }
}

trait VerticalScrollbarDecoration extends WindowDecoration {
  abstract override def draw() {
    println("in VerticalScrollbarDecoration")
    super.draw()
    // now draw a vertical scrollbar
  }
}

trait TitleDecoration extends WindowDecoration {
  abstract override def draw() {
    println("in TitleDecoration")
    super.draw()
    // now draw the title bar
  }
}

Променљиве се могу декларисати на следећи начин:

val mywin = new SimpleWindow with VerticalScrollbarDecoration with HorizontalScrollbarDecoration with TitleDecoration

Резултат позивања  mywin.draw() је

in TitleDecoration
in HorizontalScrollbarDecoration
in VerticalScrollbarDecoration
in SimpleWindow

Другим речима, позив draw се први извршава у коду  TitleDecoration (последње особине се помешају), затим (преко super() позива) с навојем назад кроз друге мешовите особине и на крају до кода  Window сам, иако ниједна особина није наследила ништа. Ово је слично обрасцу декоратора, али је више концизно и мање склон грешкама, јер не захтева експлицитни матични прозор , експлицитно прослеђивање функције чија реализација се не мења. У другим језицима, сличан ефекат се може постићи компилирањем са дугим линеарним ланцем наслеђивања имплементације , али на штету у односу да је Скала један линеарни ланац наследство ће бити проглашено за сваку могућу комбинацију микс-инс . 

Изражајни тип система

уреди

Скала је опремљена експресивног статичким типом система који намеће безбедно и кохерентно коришћење апстракција. Конкретно, тип система подржава : 

Сцала може да закључи врсте од употребе. То ради већина статичких изјаве типа опција. Статички типови не морају бити изричито изјављени, осим ако преводилац указује грешку на потребу. У пракси, неке статичке изјаве типа су укључени због јасноће кода . 

Тип обогаћивања

уреди

Заједнички техника у Скали, познат као "обогати своју библиотеку" ;[23] ова формулација се сада губи због своје конотације), омогућава да се користе нове методе као да су додати у постојећих типовима. Ово је слично C # концепту саветодавних метода, али моћније, јер техника се не ограничава на додавању поступака. У Скали, ова техника подразумева проглашење имплицитне конверзије из типа "прима" на нову врсту (обично класе), који обавија оригиналну врсту и обезбеђује додатну методу. Ако се метод не може наћи за дату врсту, преводилац аутоматски тражи било коју имплицитну конверзију врста које пружају метод у питању . 

Ова техника омогућава нове методе да се додају у постојеће класе користећи додатак библиотеци само ако код који увози додатак библиотеци добија нову функционалност, а за све остало код је непроменљив . 

Следећи пример показује обогаћивање типа

Int са методама isEven и isOdd:

object MyExtensions {
  implicit class IntPredicates(i: Int) {
    def isEven = i % 2 == 0
    def isOdd  = !isEven
  }
}

import MyExtensions._ // bring implicit enrichment into scope
4.isEven // -> true

Убацивање чланова MyExtensions доноси имплицитно претварање могућности продужења класе

IntPredicates у оквиру .[27]

Конкуренција

уреди

Стандардна библиотека Скале укључује подршку за актор модела, поред стандардних Јава конкуренција АПИ. Безбедан тип пружа платформу [28] коју укључује Акка, посебан извор оквир који омогућава актор заснован на конкуренцији. Акка актери могу бити дистрибуирани или у комбинацији са софтверском трансакционим меморијом ("трансактори"). Алтернативна ЦСП имплементација има за канал на бази поруке преко које комуницирају Скала објекти,[29] или једноставно преко ЈЦСП.

Актор као тема примера за поштанско сандуче . Може бити створена  system.actorOf, укључујући receive методу примљања порука и коришћењем ! (знак узвика ) метод да се пошаље порука .[30] Следећи пример показује ЕкоСервер који може да прима поруке и затим и и штампа.

val echoServer = actor(new Act {
  become {
    case msg => println("echo " + msg)
  }
})
echoServer ! "hi"

Скала је такође подржана паралелним програмима у форми паралелног складиштења [31] интегрисаног у стандарној библиотеци од верзије 2.9.0. Следећи пример показује коришћење паралелних складиштења перформанса.[30]

val urls = List("http://scala-lang.org", "https://github.com/scala/scala")

def fromURL(url: String) = scala.io.Source.fromURL(url)
  .getLines().mkString("\n")

val t = System.currentTimeMillis()
urls.par.map(fromURL(_))
println("time: " + (System.currentTimeMillis - t) + "ms")

Поред актора подршке и паралелизма, Скала такође подржава асинхроно програмирање са будућношћу и обећањима, софтвере трансакцијске меморије, и догађаје потока

.[32]

Кластер рачунарство

уреди

Два значајна извора кластер рачунарства су заснована на Скали: Апач Спарк и Апач Игнит (прилагођени комерцијалном ГридГејн производу) .[33] Осим тога, Апач Кафка је објавио претплатну поруку реда популарности са Спарком и другим стрим процесорима технологија, пише у Скали. 

Тестирање

уреди

Постоји неколико начина тестирања кода у Скали:

  • СkалаТест подржава више стилова тестирања и може се интегрисати са оквирима за тестирање базираним на Јави[34]
  • СкалаЧек, библиотека слична Хаскел КвикЧеку[35]
  • спецс2, библиотека за писање извршних софтверских апликација помоћу спецификација[36]
  • СкалаМок подржава тестирање функција високог реда и Кари функција[37]
  • ЈУнит или ТестИНГ, два популарна оквира за тестирање писана у Јави

Верзије

уреди
Верзија Издата Карактеристике Стање Notes
2.0[38] 12-03-2006 _ _ _
2.1.8[39] 23-08-2006 _ _ _
2.3.0[40] 23-11-2006 _ _ _
2.4.0[41] 09-03-2007 _ _ _
2.5.0[42] 02-05-2007 _ _ _
2.6.0[43] 27-07-2007 _ _ _
2.7.0[44] 07-02-2008 _ _ _
2.8.0[45] 14-07-2010 Заједничка ревизија, униформа, и свеобухватни оквир за прикупљање врста . _ _
2.9.0[46] 12-05-2011 _ _ _
2.10[47] 04-01-2013
  • Вредност класа[48]
  • Имплицитне класе[49]
  • Интерполирани стринг[49]
  • Будућност и обећања[50]
  • Динамик и еплДинамик[51]
  • Зависност типова методе: * деф идентитетом (x: ЕниРеф): x.тајп = x // враћени тип каже да је враћен 
  • Нови Бајт код емитер базиран на АСМ: Може да означи ЈДК 1.5, 1.6 and 1.7 / Емитс 1.6 бајт код / стар 1.5 бекенд је осуђен
  • нови образац подудараа: преписан од нуле да произведе више робустан код (не више експоненцијални блов-ап!) / генерисање кода и анализе су сада независни (овај други се може искључити са -Иксно-петмат-анализом)
  • Скаладок побољшања
  • Имплицитс (имплицитс застава)
  • Дијаграми (-дијаграмс застава, захтева грепвиз)
  • Групе (-групе)
  • Модуларнизоване језичке карактеристике[52]
  • Паралелне колекције[53] сада конфигурисане са навојем базена
  • Акка актори сада део дистрибуције \\ скала.акторс су застарели и имплементација Акка је сада укључена у дистрибуцију.
  • Побољшање перформанса: Бржи инлајнер / опсег # Збир је сада о (1)
  • Ажурирање ФоркЈоин библиотеке
  • Поправке у непроменљивима ТрееСет / ТрееМап
  • Побољшања парцијалних функција
  • Додавање ??? и НотИмплементедЕрор
  • Додавање ИсТраверсејблеОнсе +ИсТраверсејблеЛајк класе типа за проширење метода
  • Деприкатије и чишћење
  • Праћење тачке и окталне буквалне синтакеа негодовања
  • Враћена скала.дбц

Експерименталне карактеристике

  • Скала Рефлекције[54]
  • Макрои[55]
_ _
2.10.2[56] 06-06-2013 _ _ _
2.10.3[57] 01-10-2013 _ _ _
2.10.4[58] 18-03-2014 _ _ _
2.10.5[59] 05-03-2015 _ _ _
2.11.0[60] 21-04-2014 _ _ _
2.11.1[61] 20-05-2014 _ _ _
2.11.2[62] 22-06-2014 _ _ _
2.11.4[63] 31-10-2014 _ _ _
2.11.5[64] 08-01-2015 _ _ _
2.11.6[65] 05-03-2015 _ _ _
2.11.7[66] 23-06-2015 _ Тренутно _

Поређење са другим ЈВМ језицима

уреди

Скала је често у поређењу са Груви и Цлојуре, два друга програмска језика који користе ЈВМ. Значајне разлике између тих језика налазе се у систему типа, у мери у којој сваки језик подржава објектно-оријентисано и функционално програмирање, а у сличности њихових синтакси у синтаксама Јаве.

Скала статички тип, а како Гроови и Цлојуре су динамички типови. То чини тип систем сложенијим и тешким за разумевање, али омогућава готово да све грешке типа буде ухваћене у компилирање и може се довести до знатно бржег извршења. Насупрот томе, динамично куцање захтева више тестирања како би се осигурала исправност програма и генерално спорије како би се омогућила већа флексибилност програмирања и једноставност. Што се тиче брзине разлике, тренутне верзије Груви и Цлојуре дозвољавају опционе типове напомена да помогну програмима како би избегли изнад главе динамичног куцања у случајевима у којима типови су практично статички. Ово изнад је додатно смањено када се користе најновије верзије ЈВМ, која је појачан са "динамичним изазивањима". Упутство за методе које су дефинисане са динамичким откуцаним аргументима. Ови аванси смањују јаз између брзине статичког и динамичког куцања, иако је статички откуцан језика, као Скала, и даље омиљени избор када је ефикасност извршења веома важна.

Што се тиче програмских парадигми, Скала наслеђује објектно-оријентисани модел Јаве и проширује га на разне начине. Груви, истовремено снажно објектно- оријентисан је више усмерен на смањење евидентирања. У Цлојуре, објектно-оријентисано програмирање је димпејсед са функционалним програмирање што је главна снага језика. Скала има многе функционалне програмске садржаје, укључујући и могућности наласка у напредним функционалних језика као што су Хаскел, и покушава да буде агностик између две парадигме, пуштајући програмеру да изабере између две парадигме или, чешће, неке њихове комбинације.

Што се тиче синтаксе сличности са Јавом, Скала наслеђује много Јаве синтаксе, као што је то случај са Груви. Цлојуре са друге стране следи Lisp синтаксу, која се разликује и у изгледу и филозофији. Међутим, учење Скале се сматра тешко због његових бројних напредних функција. То није случај са Груви, упркос чињеници да је такође богат функцијама језика, углавном зато што је дизајниран да буде пре свега скриптни језик.

Прихватање

уреди

Рангирање језика

уреди

Скала је проглашена за најпопуларнији ЈВМ писаћи језик 2012. године на ЈаваУан конференције.[9]

Од 2013. године, сви деривати базирани на ЈВМ (Скала / Груви / Цлојуре) су значајно мање популарни од оригиналног Јава језика који се обично рангира као први или други,[67][68][69] а који се такође истовремено развија.

 
ТИОБЕ Скала од 2006…2015

Од децембра 2013. године,индекс ТИОБЕ[68] програмског језика популарности показује Скалу на 31. месту са 0,342% програмера (мерено Интернет претраживачима и сличним публикацијама бројања), док је испод горње границе од 50 година раније. Скала је сада испред функционалних језика Хаскел (50.) и Ерланг (> 50), као и ЈВМ конкуренти Груви (47.) и Clojure (> 50).

Друга мера, РедМонк програмски језик ранг листе, од јуна 2013. године поставља Скалу 12., заснована на 15. позицији у смислу броја ГитХуб пројеката и 16. у погледу броја питања означених на Стак Оверфлоу.[67] (Груби је био на 18. месту; Clojure на 22,.)[67] Ево, Скала је јасно иза прве класе групе од 11 језика (укључујући Јава, C, Пајтон, PHP, Руби, итд), али водећих у другој приказаној групи.

ТоутВоркс технологија радар, што је мишљење засновано на полу-годишњем извештају о групи виших технолога,[70] препоручује усвајање Скале у својим језицима и оквири категорију.[71]

Према Индид.цом Џоб Трендс, потражња Скале нагло расте од 2010. године, испред Цлојуре али иза Груви.

Компаније

уреди

У априлу 2009. године, Твитер је објаво да је укључен велики делови његовог бекхенд Руби Скале и намеру да претворити остатак.[72]

Глит користи Скалу и Плеј Фрејмворк.[28]

Форсквер користи Скалу и Лифт..[73]

СпринГоу користи Скалу и Акка.[74]

Коросера користи Скалу и Плеј Фрејмворк.[75]

Гардијан (новине)[76] најављују у априлу 2011. године да је прелазак са Јава да Сцала,[77][78]

Њујорк тајмс открива  2014. године да је интерни систем за управљање садржаја Црнобради изграђен коришћењем Скале, Акке и Пеја.[79]

Хафингтон пост новине су почеле да запошљавају Скалу као део свог система испоруке садржаја Атена 2013. године.[80]

Швајцарска банка УБС узима Скалу као главни продукциони систем.[81]

БитГолд платформа је у потпуности изграђена на Скали и Плеј Фрејмворку.[82]

ЛинкедИн користи Скалатра микрофрејмворк за напајање свој сигнал АПИ.[83]

Митап користи дефилтер алат за реално врме АПИ.[84]

Ремембер д Милк користи анфилтред алат, Скалу и Акку јавно за АПИ и ажурирања реалног времена.[85]

Веризон тражи да "следеће генерације раде" помоћу Скале.[86]

Замерка

уреди

У новембру 2011. године, Јамер је напустио Скалу због стрме криве учења нових чланова тима и некомпатибилности претходних са следећим верзијама Скала преводиоца.[87] Други критикују Скалу због нечитљивости везаних за имплицитне параметре, и због тога што није могуће избећи Скалине више арканске карактеристике када се повуче библиотека која их користи, те да све у свему, "Тежина Скале превазилази њену вредност."[88][89]

Референце

уреди
  1. ^ „Scala 2.11.7 is now available!”. 23. 6. 2015. Приступљено 3. 7. 2015. 
  2. ^ „Scala.js”. Приступљено 27. 7. 2015. 
  3. ^ „Scala 2.11.1 is now available!”. 
  4. ^ „Clojure Programming” (PDF). Приступљено 2013-04-30. 
  5. ^ а б в Martin Odersky et al., An Overview of the Scala Programming Language, 2nd Edition
  6. ^ "Frequently Asked Questions - Java Interoperability". scala-lang.org
  7. ^ Loverdo 2010
  8. ^ а б в Martin Odersky, "A Brief History of Scala", Artima.com weblogs, June 9, 2006
  9. ^ а б в г д Odersky, M.; Rompf, T. (2014).
  10. ^ Martin Odersky, "The Scala Language Specification Version 2.7"
  11. ^ Expunged the .net backend. by paulp · Pull Request #1718 · scala/scala · GitHub.
  12. ^ "Scala Team Wins ERC Grant"
  13. ^ "Commercial Support for Scala". 2011-05-12
  14. ^ "Why We Invested in Typesafe: Modern Applications Demand Modern Tools" Архивирано на сајту Wayback Machine (8. децембар 2012). 2011-05-12
  15. ^ "Open-source Scala gains commercial backing". 2011-05-12
  16. ^ "Cloud computing pioneer Martin Odersky takes wraps off his new company Typesafe". 2011-05-12
  17. ^ "Developing for Android"
  18. ^ "Scala Js Is No Longer Experimental | The Scala Programming Language" Архивирано на сајту Wayback Machine (2. октобар 2015).
  19. ^ "Scala License | The Scala Programming Language".
  20. ^ "Getting Started with Scala". scala-lang.org. 15. 7. 2008
  21. ^ "Home" Архивирано на сајту Wayback Machine (31. август 2010).
  22. ^ Scala's built-in control structures such as if or while cannot be re-implemented.
  23. ^ а б "Pimp my Library".
  24. ^ "Collections - Concrete Immutable Collection Classes - Scala Documentation"
  25. ^ Rich Dougherty.
  26. ^ "TailCalls - Scala Standard Library API (Scaladoc) 2.10.2 - scala.util.control.
  27. ^ Implicit classes were introduced in Scala 2.10 to make method extensions more concise.
  28. ^ а б Typesafe Inc.
  29. ^ Communicating Scala Objects, Bernard Sufrin, Communicating Process Architectures 2008
  30. ^ а б Kay Yan.
  31. ^ "Parallelcollections - Overview - Scala Documentation".
  32. ^ Frank, Felix (28. 11. 2014). Learning Concurrent Programming in Scala. Packt Publishing. ISBN 978-1783281411. 
  33. ^ Murphy, Ian (2014-11-04).
  34. ^ Kops, Micha (2013-01-13).
  35. ^ Nilsson, Rickard (2008-11-17).
  36. ^ "Build web applications using Scala and the Play Framework". workwithplay.com. 2013-05-22
  37. ^ Butcher, Paul (2012-06-04).
  38. ^ "Changes in Version 2.0 (12-Mar-2006)". scala-lang.org. 2006-03-12
  39. ^ "Changes in Version 2.1.8 (23-Aug-2006)". scala-lang.org. 2006-08-23
  40. ^ "Changes in Version 2.3.0 (23-Nov-2006)". scala-lang.org. 2006-11-23
  41. ^ "Changes in Version 2.4.0 (09-Mar-2007)". scala-lang.org. 2007-03-09
  42. ^ "Changes in Version 2.5 (02-May-2007)". scala-lang.org. 2007-05-02
  43. ^ "Changes in Version 2.6 (27-Jul-2007)". scala-lang.org. 2007-06-27
  44. ^ "Changes in Version 2.7.0 (07-Feb-2008)". scala-lang.org. 2008-02-07
  45. ^ "Changes in Version 2.8.0 (14-Jul-2010)". scala-lang.org. 2010-07-10
  46. ^ "Changes in Version 2.9.0 (12-May-2011)". scala-lang.org. 2011-05-12
  47. ^ "Changes in Version 2.10.0". scala-lang.org. 2013-01-04
  48. ^ Harrah, Mark.
  49. ^ а б Suereth, Josh.
  50. ^ Haller, Philipp; Prokopec, Aleksandar.
  51. ^ "SIP-17 - Type Dynamic". scala-lang.org
  52. ^ "SIP-18 - Modularizing Language Features". scala-lang.org
  53. ^ Prokopec, Aleksandar; Miller, Heather.
  54. ^ Miller, Heather; Burmako, Eugene.
  55. ^ Burmako, Eugene.
  56. ^ "Scala 2.10.2 is now available!". scala-lang.org. 2013-06-06
  57. ^ "Scala 2.10.3 is now available!". scala-lang.org. 2013-10-01
  58. ^ "Scala 2.10.4 is now available!". scala-lang.org. 2014-03-18
  59. ^ "Scala 2.10.5 is now available!". scala-lang.org. 2015-03-04
  60. ^ "Scala 2.11.0 is now available!". scala-lang.org. 2014-04-21
  61. ^ "Scala 2.11.1 is now available!". scala-lang.org. 2014-05-20
  62. ^ "Scala 2.11.2 is now available!". scala-lang.org. 2014-07-22
  63. ^ "Scala 2.11.4 is now available!". scala-lang.org. 2014-10-31
  64. ^ "Scala 2.11.5 is now available!". scala-lang.org. 2015-01-08
  65. ^ "Scala 2.11.6 is now available!". scala-lang.org. 2015-03-05
  66. ^ "Scala 2.11.7 is now available!". scala-lang.org. 2015-06-23
  67. ^ а б в "The RedMonk Programming Language Rankings: June 2013".
  68. ^ а б "TIOBE Index for December 2013" Архивирано на сајту Wayback Machine (2. јул 2013).
  69. ^ "The Transparent Language Popularity Index, July 2013".
  70. ^ "ThoughtWorks Technology Radar FAQ".
  71. ^ "ThoughtWorks Technology Radar MAY 2013" (PDF).
  72. ^ Greene, Kate (April 1, 2009).
  73. ^ "Scala, Lift, and the Future" Архивирано на сајту Wayback Machine (13. јануар 2016)
  74. ^ "SpinGo - SpinGo + Scala"
  75. ^ Coursera Engineering.
  76. ^ David Reid and Tania Teixeira (26 February 2010).
  77. ^ "Guardian switching from Java to Scala".
  78. ^ "Guardian.co.uk Switching from Java to Scala".
  79. ^ Roy, Suman and Sundaresan, Krishna (2014-05-13).
  80. ^ Pavley, John (2013-08-11).
  81. ^ Binstock, Andrew (2011-07-14).
  82. ^ http://www.bitgold.com | BitGold built on Scala and Play Framework
  83. ^ Synodinos, Dionysios G. (2010-10-11).
  84. ^ "Real-life Meetups Deserve Real-time APIs".
  85. ^ "Real time updating comes to the Remember The Milk web app".
  86. ^ "Senior Scala Engineer"
  87. ^ Hale, Coda (29 November 2011).
  88. ^ Allan, Graham (23 June 2013).
  89. ^ Pollack, David (14 September 2011).

Литература

уреди

Спољашње везе

уреди