• Like
  • Save
Scala Magic, Alexander Podhaliusin
Upcoming SlideShare
Loading in...5
×
 

Scala Magic, Alexander Podhaliusin

on

  • 1,101 views

Talk given by Alexander Podhaliusin at scaladev'12 (scaladev.ru)

Talk given by Alexander Podhaliusin at scaladev'12 (scaladev.ru)

Statistics

Views

Total Views
1,101
Views on SlideShare
686
Embed Views
415

Actions

Likes
0
Downloads
4
Comments
0

2 Embeds 415

http://scala.by 410
http://localhost 5

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Scala Magic, Alexander Podhaliusin Scala Magic, Alexander Podhaliusin Presentation Transcript

    • Scala magicАлександр Подхалюзин 19 мая 2012 г. 1 / 19
    • Syntactic sugarForcomprehensionsBy-nameparametersNon local returnLocal functionsLazy valuesGeneratedByteCodeBinary Syntactic sugarcompatibilityQuestions? 2 / 19
    • For comprehensionsSyntactic sugarFor В Scala for является синтаксическим сахаром, тем неcomprehensionsBy-name менее правила преобразования довольно сложныparametersNon local return Один генератор с ’yield’ тоже, что вызов метода ’map’Local functionsLazy values Один генератор без ’yield’ тоже, что ’foreach’Generated Несколько генераторов транслируются во ’flatMap’ByteCodeBinarycompatibilityQuestions? f o r ( i <− 1 t o 5) (1 to 5) . map { i = i > i } yield i i (1 to 5) . f o r e a c h { f o r ( i <− 1 t o println ( i ) 5)   } i = println ( i ) > f o r { i <− 1 t o 5 (1 to 5) . f l a t M a p { j <− 1 t o 5} i = (1 to 5) . map { j = i + j } > > yield i + j } Подробнее можно почитать в спецификации. 3 / 19
    • By-name parametersSyntactic sugarFor Возможность в вызов метода передавать выраженияcomprehensionsBy-name лениво это другой пример того, где неявно могут бытьparametersNon local return зашиты closures. Следующие два примера идентичны:Local functionsLazy values d e f foo ( x : => Int ) { d e f foo ( x : ( ) => Int ) {GeneratedByteCode println ( x ) println ( x ( ) ) } }Binarycompatibility foo ( 1 ) foo ( ( ) => 1 )Questions? Что изредка может приводить к ошибке (параметр будет вычисляться каждый раз, когда к нему будет производится обращение). 4 / 19
    • Non local returnSyntactic sugarFor Return statement внутри closure на деле компилируется вcomprehensionsBy-name код, который бросает NonLocalReturnControl. ВparametersNon local return большинстве случаев это удобно, но нужно учитыватьLocal functions следующееLazy valuesGenerated В критичных по производительности кусках кода этотByteCodeBinary exception следует избегатьcompatibility Нельзя ловить Throwable в том месте, где этотQuestions? exception бросается В силу синтаксического сахара описанного ранее, все это может происходить неявно (for-comprehensions и by-name parameters) 5 / 19
    • Local functionsSyntactic sugarFor В Java любой вспомогательный код оформляется в видеcomprehensionsBy-name private методов на уровне класса. В Scala это можноparametersNon local return сделать более структурированным, если использоватьLocal functions локальные методы, хотя на уровне bytecode получаетсяLazy valuesGenerated примерно тоже самое:ByteCodeBinarycompatibility import scala . runtime . IntRef ; public class LocalFunctions {Questions? class LocalFunctions { p u b l i c void foo () { def foo { I n t R e f i $ 1 = new I n t R e f ( 1 ) ; var i = 1 i n t j$1 = 2; val j = 2 l o c a l $ 1 ( i$1 , j$1 ) ; def local { i += j   l o c a l $ 1 ( i$1 , j$1 ) ; } } p r i v a t e f i n a l void local$1 ( local IntRef intref , i n t i ) { local i n t r e f . e l e m += i ; } } } p u b l i c L o c a l F u n c t i o n s ( ) {} } 6 / 19
    • Lazy valuesSyntactic sugarFor Это тоже синтаксический сахар, который надоcomprehensionsBy-name использовать аккуратно (так как возможны deadlock иparametersNon local return проблемы производительности). Независимо отLocal functions расположения lazy val, компилируется он таким образомLazy valuesGeneratedByteCode import scala . runtime . BoxedUnit ;Binary p u b l i c c l a s s Lazy {compatibility public int x () { i f ( ( b i t m a p $ 0 & 2 ) == 0 )Questions? synchronized ( this ) { i f ( ( b i t m a p $ 0 & 2 ) == 0 ) { x = 1; bitmap$0 = bitmap$0 | 2; c l a s s Lazy { lazy val x = 1   } BoxedUnit _tmp = } BoxedUnit . UNIT ; } return x ; } p u b l i c L a z y ( ) {} private int x ; public v o l a t i l e i n t bitmap$0 ; } 7 / 19
    • Syntactic sugarGeneratedByteCodeClasses and namesObjectsTraitsTrait subclassesLinearizationInitialisation orderBinary Generated ByteCodecompatibilityQuestions? 8 / 19
    • Classes and namesSyntactic sugar Для классов ничего магического не происходит.GeneratedByteCode Как преобразуются имена. Для большинства символовClasses and namesObjects есть его текстовый эквивалентTraitsTrait subclasses :   $colonLinearizationInitialisation order +   $plusBinary ©   $u00A9compatibilityQuestions? Внутри Scala кода можно использовать оба варианта подобных идентификаторов Подробнее можно изучить преобразования с помощью методов NameTransfomer.encode/decode из scala-compiler.jar. 9 / 19
    • ObjectsSyntactic sugar Объект всегда компилируется в два класса.GeneratedByteCodeClasses and names Object$ содержит в себе статическое поле MODULE$,Objects а также код всех методовTraitsTrait subclasses Object содержит в себе все статические методыLinearizationInitialisation order объекта, с телом вида Object$.MODULE$.foo()Binarycompatibility Важно понимать, что статические методы добавлены дляQuestions? удобства вызова из Java. Тем не менее они добавляются не всегда. В Companion Trait не добавляется ничего. В Companion Class не добавляются методы с таким именем, которое уже есть в этом классе Методы класса java.lang.Object 10 / 19
    • TraitsSyntactic sugar Если trait отличается от обычного интерфейса в JavaGeneratedByteCode наличием конкретных методов, то к соответствующемуClasses and namesObjects интерфейсу будет создан класс Trait$class сTraitsTrait subclasses имплементацией этих методов.LinearizationInitialisation orderBinary public abstract class A$class {compatibility public static int foo ( A $this , int x) {Questions? return 2; trait A { } val x = 1   public s t a t i c void $init$ ( A $this def foo ( x : Int ) = 2 ) { } $this . test$A$_setter_$x_$eq (1) ; } } 11 / 19
    • Trait subclassesSyntactic sugar Если в Java попытаться реализовать Trait, в котором естьGeneratedByteCode уже имплементированые методы, то их все равноClasses and namesObjects пришлось бы реализовывать. Другой вопрос, что этоTraitsTrait subclasses можно сделать предельно легко:LinearizationInitialisation orderBinary i n t foo ( ) { r e t u r n Trait$class . foo ( t h i s ) ; }compatibilityQuestions? В случае наследников написанных на Scala, то же самое делает компилятор. 12 / 19
    • LinearizationSyntactic sugar Этот алгоритм требуется компилятору, чтобы определить,GeneratedByteCode в каком порядке надо искать методы в базовых классах.Classes and namesObjectsTraitsTrait subclasses trait A extends BLinearization trait BInitialisation order class C extends BBinary class D extends C with AcompatibilityQuestions? Здесь порядок D, A, C, B. Если два метода с одинаковой сигнатурой без модификатора ’override’ приходят в класс наследник из супертрейтов, то ошибки не будет, так как обязательно надо будет переопределить эту сигнатуру. Если же у кого-то есть модификатор ’override’, может случится неявный override согласно правилам линеаризации. 13 / 19
    • Initialisation orderSyntactic sugar Инициализация происходит в порядке, обратномGeneratedByteCode линеаризации. Если к переменной обратиться до того, какClasses and namesObjects она проинициализирована, можно получить NPE.TraitsTrait subclasses Есть два способа избавится от подобных проблем:LinearizationInitialisation order Использовать lazy valBinarycompatibility Использовать early definitionsQuestions? 14 / 19
    • Syntactic sugarGeneratedByteCodeBinarycompatibilityMethodsValuesLazy valuesQuestions? Binary compatibility 15 / 19
    • MethodsSyntactic sugar Здесь все очень похоже на Java. Чаще всего проблем неGeneratedByteCode будет.Binarycompatibility Добавлять метод можно даже в Trait, но только еслиMethodsValues старые методы не ссылаются на новые, так какLazy values имплементации в классы наследники добавлены неQuestions? будут. В класс опасно добавлять методы, имена которых совпадают с именем методов из Companion Object, так как статические реализации будут удалены компилятором, что может вызвать проблемы с кодом написанным не на Scala. 16 / 19
    • ValuesSyntactic sugar Если переменная находится в классе или объекте, тоGeneratedByteCode переменная компилируется в getter, setter (для variables) иBinarycompatibility field, который инциализируется в конструкторе класса. АMethods значит все будет также хорошо как и с методами.ValuesLazy values Если переменная находится в Trait, то она компилируетсяQuestions? в getter и setter (всегда). Инициализация происходит в методе Trait$class.$init$ через вызов setter. Значит добавлять переменную в трейт нельзя. Так как будет вызван абстрактный setter. По аналогичным причинам нельзя изменять def на val Тем не менее val на def также изменять нельзя, так как тогда в классах наследниках, где как раз и хранится field, переменная не будет проинициализирована. 17 / 19
    • Lazy valuesSyntactic sugar В подклассах не генерируется field bitmap, если он есть вGeneratedByteCode базовом классе.Binarycompatibility Поэтому в этих случаях добавлять lazy value в классыMethodsValues нельзяLazy values В Trait добавлять можно, если эта переменная неQuestions? будет использована в старом коде Так как компиляция lazy val в Trait от компиляции метода не отличается совсем, то их можно заменять друг на друга, учитывая только, что в наследниках подобная семантика не изменится 18 / 19
    • Syntactic sugarGeneratedByteCodeBinarycompatibilityQuestions? Questions? 19 / 19