Upload
daniel-sobral
View
1.201
Download
1
Embed Size (px)
DESCRIPTION
Scala 2.10.0 -- de onde viemos, e para onde vamos? Breve olhar nas funcionalidades a serem introduzidas por Scala 2.10.0. Nota: Scala 2.10.0 não foi lançada, e a versão final terá diferenças em relação ao apresentado.
Citation preview
Scala 2.10De onde viemos e para onde vamos?
Daniel Capó Sobral
Quem sou eu?Daniel C. Sobral @ Stack Overflowdcsobral @ Twitter, Gmail/Gtalk, Skype,
SliderShareDaniel Sobral @ Facebook, Speakers Deck,
LinkedInhttp://www.linkedin.com/in/danielsobralhttp://www.slideshare.net/dcsobralhttps://speakerdeck.com/u/dcsobralhttp://dcsobral.blogspot.com
O que eu sei de Scala?Scala gold badge @ Stack OverflowPequenas contribuições para Scala:
otimizaçõesfuncionalidadesbug fixesdocumentação (nem tão pequenas)
Participante ativo da comunidade Scala (listas de discussão, irc)
Blog
IMPORTANTE!Scala 2.10.0 ainda não foi lançada!
Na data em que esta apresentação foi escrita... (07/07/2012)
As informações contidas nessa apresentação podem mudar antes do lançamento.
SumárioHistóricoFuturo Imediato
VersionamentoProcesso de ReleaseBug fixesMelhoriasSIPs (Scala Improvement Process)ReflectionAtores e Akka
Futuro Distante
O passado
Histórico
• 2.9.2
2012
• 2.9.0
• 2.9.1
• 2.8.2
2011
• 2.8.0
• 2.8.1
2010
• 2.7.3
• 2.7.4
• 2.7.5
• 2.7.6
• 2.7.7
2009
• 2.7.1
• 2.7.2
2008
• 2.3.2
• 2.3.3
• 2.4.0
• 2.5.0
• 2.5.1
• 2.6.0
• 2.6.1
2007
• 2.0.0
• 2.1.0
• 2.1.1
• 2.1.2
• 2.1.3
• 2.1.5
• 2.1.6
• 2.1.7
• 2.1.8
• 2.2.0
• 2.3.0
• 2.3.1
2006
• 1.4.0
2005
• 1.0.0
• 1.1.0
• 1.1.0
• 1.1.1
• 1.2.0
• 1.3.0
2004
• 0.8.1
• 0.8.2
• 0.9.0
• 0.9.1
2003
Alguns marcos importantes
2006• Scalac escrito em Scala
• Implicits• Traits e linearização
• Multilline Strings
2007• Extractors• Private/protected primary constructors
• Private[this]• Placeholder parameters
• Early Initialization• Abstract Type Constructors
• Existential Types• Lazy values• Structural Types
2008• Java Generics• Case Class Extractors
2010• Novo design de Collections
• Compatibilidade Binária
2011• Parallel Collections
O futuro imediato
Explicando Versionamento
2
Epoch
.9
Major
.1
Minor
-1
Bug fix
Versionamento – Scala 2.10.0Major releaseBinariamente incompatívelMudanças de linguagemMudanças de bibliotecaNovas depreciaçõesRemoção de características depreciadas
(deprecated)ClassesMétodosCaracterísticas da linguagem
Exemplos de Novas DepreciaçõesNúmeros octais!
Double terminando em ponto
scala> 077<console>:1: warning: Treating numbers with a leading zero as octal is deprecated. 077 ^res10: Int = 63
scala> 1.<console>:1: warning: This lexical syntax is deprecated. From scala 2.11, a dot willonly be considered part of a number if it is immediately followed by a digit. 1. ^res11: Double = 1.0
Exemplos de Depreciações RemovidasCaracterísticas de linguagem
Classe
Método
Pacotes
for ( val i <- 1 to 10) println(i)
scala.collection.mutable.CloneableCollection
scala.collection.immutable.Queue.+
scala.testing.SUnit
Melhoria no processo de releaseProcesso cada vez mais automatizadoPacotes RPM, APT, Brew, etc
Geração automática!Uso de Milestones para integrar ferramentas
de terceirosM4 dia 12 de JunhoM5 em breve
Release Candidates para consolidar e eliminar bugs
Bug fixesMuitas correções!Novo código do pattern matcher!Priorização da correção de tickets!Novos warnings:
Detectando bugs no próprio compilador!Mais contribuições de terceiros!
git + pull request == FTW...em adição ao processo natural de melhoria
da linguagem.
Tickets fechados102 451 490 622 896 963 1118 1133 1195 1201 1247 1336
1430 1431 1432 1439 1510 1785 1799 2089 2094 2171 2196 2308
2322 2337 2388 2405 2435 2442 2460 2764 2782 2807 3047 3048
3098 3240 3272 3326 3343 3371 3392 3481 3566 3569 3628 3702
3708 3718 3755 3758 3761 3770 3798 3853 3854 3880 3898 3929
3960 3999 4018 4019 4025 4027 4063 4070 4098 4110 4124 4134
4147 4171 4172 4176 4216 4262 4270 4271 4273 4319 4326 4336
4355 4372 4391 4398 4417 4419 4425 4430 4441 4461 4467 4469
4478 4482 4490 4494 4501 4510 4512 4515 4535 4540 4541 4542
4547 4553 4561 4568 4570 4573 4574 4578 4579 4584 4592 4593
4595 4599 4601 4627 4636 4642 4647 4651 4656 4658 4661 4692
4696 4697 4709 4712 4713 4716 4717 4723 4727 4731 4737 4740
4749 4753 4757 4758 4759 4761 4764 4766 4770 4777 4780 4792
Tickets fechados4794 4800 4802 4804 4807 4809 4811 4818 4823 4827 4828 4831
4833 4839 4842 4846 4851 4853 4857 4858 4859 4860 4861 4869
4871 4874 4875 4877 4879 4882 4891 4894 4898 4899 4909 4910
4911 4925 4928 4929 4933 4935 4938 4954 4957 4959 4961 4963
4970 4975 4976 4979 4981 4985 4987 4989 5005 5009 5012 5018
5020 5023 5026 5029 5032 5033 5034 5037 5040 5041 5053 5054
5056 5062 5063 5066 5071 5072 5077 5078 5080 5083 5084 5085
5093 5096 5097 5099 5104 5105 5108 5117 5119 5121 5125 5127
5135 5137 5147 5148 5152 5156 5162 5165 5167 5168 5175 5176
5178 5189 5199 5201 5205 5206 5210 5212 5215 5223 5226 5229
5230 5239 5245 5248 5256 5259 5266 5267 5272 5284 5287 5291
5293 5295 5300 5305 5313 5317 5318 5328 5334 5336 5341 5343
5344 5352 5354 5356 5358 5359 5373 5374 5375 5377 5382 5384
Tickets fechados (442 – 02/Jul)5387 5399 5405 5406 5407 5426 5428 5429 5441 5444 5446 5451
5452 5453 5455 5471 5488 5489 5497 5500 5510 5514 5522 5528
5530 5532 5535 5537 5542 5543 5544 5545 5552 5553 5554 5564
5571 5572 5577 5578 5580 5589 5590 5591 5593 5599 5608 5609
5610 5612 5614 5617 5623 5626 5627 5629 5632 5640 5641 5644
5648 5652 5654 5655 5656 5663 5666 5667 5672 5676 5677 5680
5682 5683 5688 5689 5690 5693 5696 5702 5703 5704 5706 5707
5708 5713 5715 5720 5728 5729 5735 5738 5742 5760 5761 5763
5769 5777 5779 5796 5801 5804 5805 5809 5816 5821 5829 5839
5840 5843 5845 5846 5853 5857 5862 5867 5879 5880 5881 5899
5910 5912 5914 5932 5953 5966 5967 5968 5971 5986 etc?
MelhoriasNovas coleções
Mutable SortedSet/SortedMap (baseadas em AVL)Mutable Concurrent Map (TrieMap)Parallel Mutable Concurrent Map (ParTrieMap)
Performance:Immutable SortedSet/SortedMap
Novo (private) RedBlackTree TreeIterator
PartialFunction applyOrElse
BitSetMurmurHash3 (coleções, xml, case classes)
NovidadesType Classes:
Try (alternativa do Twitter ao Either)Hashing (já existe Equiv)IsTraversableOnce e IsTraversableLike
Pacote scala.util.hashingPools configuráveis em coleções paralelas@unspecializedto[Collection]???
Novidadesoverride object (-Yoverride-objects)Bytecode versão 49, 50 e 51 (-target:jvm-1.x-asm)
-optimize mais rápido e eficiente-Dscala.timings=true revela quais são os pontos
de demora na compilaçãoSIP-18: -language:XXX, -featurelogs variadosmacro variadospatmat variadosetc...
scala.util.Try
def percentCompleted(total: Int, done: Int): Int = Try ( done * 100 / total ) getOrElse 100
scala.util.TryTry { new FileInputStream(a)} rescue { case _: FileNotFoundException => new FileInputStream(b)} recover { case _: FileNotFoundException => defaultInputStream} andThen { stream => in = stream.read(); Stream.close(); in}
scala.util.hashing.Hashing
def hashingOf[T : Hashing](obj: T): Int = implicitly[Hashing[T]].hash(obj)
// Uma função de hashing ruim para Seqsimplicit val seqHashing = Hashing fromFunction ((_: Seq[_]).size)
IsTraversableOnceIsTraversableLike
class FilterMapImpl[A, Repr] (val r: GenTraversableLike[A, Repr]) { final def filterMap[B, That] (f: A => Option[B]) (implicit cbf: CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)}
// Como escrever a conversão implícita???
Problemas em se escrever a conversão:Array e String não são GenTraversableString não possui parâmetro de elemento (A)Nem BitSet e outras coleçõesInferência sobre view bounds é deficiente
IsTraversableOnceIsTraversableLike
IsTraversableOnceIsTraversableLike
class FilterMapImpl[A, Repr] (val r: GenTraversableLike[A, Repr]) { final def filterMap[B, That] (f: A => Option[B]) (implicit cbf: CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)}
implicit def filterMap[Repr, A](r: Repr) (implicit fr: IsTraversableOnce[Repr]) : FilterMapImpl[fr.A,Repr] = new FilterMapImpl(fr.conversion(r))
Pools Configuráveis em Coleções Paralelasimport scala.collection.parallel._val pc = mutable.ParArray(1, 2, 3)
pc.tasksupport = new ForkJoinTaskSupport( new scala.concurrent.ForkJoinPool(2))
pc map { _ + 1)
pc.tasksupport = new ThreadPoolTaskSupport()
Pools Configuráveis em Coleções Paralelas – Customizandoclass customTaskSupport extends TaskSupport { def execute[R, Tp] (task: Task[R, Tp]): () => R = ???
def executeAndWaitResult[R, Tp] (task: Task[R, Tp]): R = ???
def parallelismLevel: Int = ???}
to[Collection]scala> List(2, 1, 3).to[Seq]res17: Seq[Int] = Vector(2, 1, 3)
scala> List(2, 1, 3).to[Vector]res18: Vector[Int] = Vector(2, 1, 3)
scala> List(2, 1, 3).to[collection.mutable.Seq]res19: scala.collection.mutable.Seq[Int] = ArrayBuffer(2, 1, 3)
scala> List(2, 1, 3).to[collection.immutable.SortedSet]res20: scala.collection.immutable.SortedSet[Int] = TreeSet(1, 2, 3)
?????? é um método do tipo Nothing que lança
uma exceçãoPor ser do tipo Nothing, ??? pode aparecer
no lugar de qualquer expressãoExcelente para stubs, exercícios e
apresentações!
???trait Opt [A] { // Exercise by Tony Morris def fold[X](some: A => X, none: => X): X = ??? def map[B](f: A => B): Opt[B] = ??? def get: A = ??? def flatMap[B](f: A => Opt[B]): Opt[B] = ??? def mapAgain[B](f: A => B): Opt[B] = ??? def getOrElse(e: => A): A = ??? def filter(p: A => Boolean): Optional[A] = ??? def exists(p: A => Boolean): Boolean = ??? def forall(p: A => Boolean): Boolean = ??? def foreach(f: A => Unit): Unit = ??? def isDefined: Boolean = ??? def orElse(o: => Opt[A]): Opt[A] = ??? // etc
Adaptado de Tony Morris, http://blog.tmorris.net/further-understanding-scalaoption/
???trait Opt [A] { // Exercise by Tony Morris def fold[X](some: A => X, none: => X): X = ??? def map[B](f: A => B): Opt[B] = ??? def get: A = ??? def flatMap[B](f: A => Opt[B]): Opt[B] = ??? def mapAgain[B](f: A => B): Opt[B] = ??? def getOrElse(e: => A): A = ??? def filter(p: A => Boolean): Optional[A] = ??? def exists(p: A => Boolean): Boolean = ??? def forall(p: A => Boolean): Boolean = ??? def foreach(f: A => Unit): Unit = ??? def isDefined: Boolean = ??? def orElse(o: => Opt[A]): Opt[A] = ??? // etc
Adaptado de Tony Morris, http://blog.tmorris.net/further-understanding-scalaoption/
MelhoriasScaladoc
Implicits!Diagramas!
API docs
ScalaDoc & Implicits
Parallel Collections Docs!
Diagramas de Classe!
Parâmetros para ScalaDoc-implicits-diagrams
Esse slide foi exigência de Vlad Ureche ;-)
SIP – Scala Improvement ProcessSIP-11: String InterpolationSIP-12: Sintaxe das Estruturas de ControleSIP-13: Classes ImplicitasSIP-14: Futures e PromisesSIP-15: Value ClassesSIP-16: Macros auto-limpantesSIP-17: Tipo DynamicSIP-18: Modularização de funcionalidades da
linguagemSIP-19: Posição de Código Fonte Implícitas
SIP – Scala Improvement ProcessSIP-11: String Interpolation (aceita!)SIP-12: Sintaxe das Estruturas de Controle (adiada)SIP-13: Classes Implicitas (aceita!)SIP-14: Futures e Promises (aceita!)SIP-15: Value Classes (aceita!)SIP-16: Macros auto-limpantes (adiada)SIP-17: Tipo Dynamic (aceita!)SIP-18: Modularização de funcionalidades da
linguagem (aceita!)SIP-19: Posição de Código Fonte Implícitas (recusada)
SIP-11: String InterpolationAusência de interpolação de strings motivo de
constante reclamaçõesMas bem poucas linguagens suportam!
Odersky diz que diferença entre ${x} e "+x+" é de um único caracterMas ignora os shifts...Alegação de que " e + no teclado Suíco não precisa
de shift Verdade!
Reviravolta:E se interpolação de strings for mais do que
interpolação de strings?
SIP-11: String Interpolationdef hello(name: String = "world"): String = "Hello, " + name + "! "
// Interpolation!def hello(name: String = "world"): String = s"Hello, $name! "
SIP-11: String Interpolationdef percentCompleted(total: Int, done: Int): String = Try ( done * 100 / total ) map { percent => f"$percent%2d% completed" } getOrElse "100% completed"
def percentCompleted(total: Int, done: Int): String = Try ( f"${ done * 100 / total }%2d% completed" ) getOrElse "100% completed"
SIP-11: String Interpolation:Como funciona?s"Hello, $name!" // traduzido paraStringContext("Hello, ", "!").s(name)
f"${ done * 100 / total }%2d% completed" // traduzido paraStringContext("", "%2d% completed").f(done * 100 / total)
SIP-11: String InterpolationLiterais multi-linha também são aceitos
s"""Ok!"""Interpolação pode ser aninhada
s"${ s"$x" }"Contra-barra não é interpretada
r"\d+/$mes" // interpolador r não existe!StringContext("""\d+/""").r(mes)
Mas s e f interpretam as barras!s"Hello, $name!\n" // newline normal
Formas de alterar comportamento:Adição de métodos implícitos à StringContextSobreposição de objeto ou método chamado StringContext“r” não precisa ser método!
SIP-11: String Interpolation// Adição de interpolação via implicitclass RegexContext(sc: StringContext) { def r(args: Any*) = { sc.checkLengths(args: _*) val res = (args, sc.parts.tail).zipped map { (arg, part) => s"\\Q$arg\\E$part" } mkString "" (sc.parts.head + res).r }}
implicit def toRC(sc: StringContext) = new RegexContext(sc)
SIP-11: String Interpolation// Aninhamento de interpoladoresclass RegexContext(sc: StringContext) { def r(args: Any*) = { sc.checkLengths(args: _*) s"${sc.parts.head}${ (args, sc.parts.tail).zipped map { (arg, part) => s"\\Q$arg\\E$part" } mkString "" }".r }}
implicit def toRC(sc: StringContext) = new RegexContext(sc)
SIP-11: String Interpolation// Adição de interpolação via sobreposiçãoobject StringContext(parts: String*) { def r(args: Any*) = { require(parts.length == args.length + 1) val res = (args, parts.tail).zipped map { "\\Q" + _ + "\\E" + _ } mkString "" (parts.head + res).r }}
// Possível alterar s e f!
SIP-11: String Interpolation// apply e unapplySeq
def hello(name: String = "world"): String = i"Hello, $name!"
def who(message: String): String = message match { case i"Hello, $name!" => name case _ => “no clue"}
who(hello("Daniel")) == "Daniel"
SIP-11: String Interpolation// apply e unapplySeqimplicit class SI(sc: StringContext) { object i { def apply(args: Any*): String = sc.parts.head + (args,sc.parts.tail).zipped.map(_+_).mkString def unapplySeq(s: String): Option[Seq[String]] = { val partsr = sc.parts map (p => s"\\Q$p\\E") val r = (partsr mkString "(.*)").r s match { case r(xs @ _*) => Some(xs) case _ => None } } }}
SIP-13: Classes Implícitas“Enrich My Library” (antigo “Pimp My
Library”) extremamente popularMas cerimonioso...“Extension methods” se tornando comuns em
outras linguagensE com menos cerimônia!
Solução: implicit class
SIP-13: Classes Implícitas// Adição de interpolação via implicit classimplicit class RegexContext(sc: StringContext) { def r(args: Any*) = { sc.checkLengths(args: _*) val res = (args, sc.parts.tail).zipped map { "\\Q" + _ + "\\E" + _ } mkString "" (sc.parts.head + res).r }}
SIP-14: Futures and PromisesExecutar operações em paralelo, de forma não-
bloqueante é uma necessidade comumEvidência: diversas bibliotecas contém
implementações de FutureIncluindo a biblioteca padrão de atores!
Problema:Interface não-padronizadaDependência de implementação
Solução:API poderosa e flexível implementando os
conceitos de Future e Promise
SIP-14: Futures and Promises// TODO – Desculpem! Exemplos da SIP:
import scala.concurrent._val f: Future[List[String]] = future { session.getRecentPosts}f onComplete { case Right(posts) => for (post <- posts) render(post) case Left(t) => render("An error has occured: " + t.getMessage)}
SIP-14: Futures and Promises// TODO – Desculpem! Exemplos da SIP:
import scala.concurrent._val f: Future[List[String]] = future { session.getRecentPosts}f onFailure { case t => render("An error has occured: " + t.getMessage)} onSuccess { case posts => for (post <- posts) render(post)}
SIP-14: Futures and Promises// TODO – Desculpem! Exemplos da SIP:
import scala.concurrent._def main(args: Array[String]) { val rateQuote = future { connection.getCurrentValue(USD) } val purchase = rateQuote map { quote => if (isProfitable(quote)) connection.buy(amount, quote) else throw new Exception("not profitable") } blocking(purchase, 0 ns)}
SIP-14: Futures and Promises// TODO – Desculpem! Exemplos da SIP:
import scala.concurrent.{ future, promise }val p = promise[T]val f = p.futureval producer = future { val r = produceSomething() p success r continueDoingSomethingUnrelated()}val consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() }}
SIP-15: Value ClassesA maldição das referênciasA maldição do boxing:
case class Meter(n: Int) muito mais “caro” que int
A maldição do das classes implícitas:"abc“.r cria um objeto desnecessário só para
chamar new Regex("abc")Queremos uma classe que não seja
referência!Solução: value classes.
SIP-15: Value Classes// Adição de interpolação via implicit value classimplicit class RegexContext(sc: StringContext) extends AnyVal { def r(args: Any*) = { sc.checkLengths(args: _*) val res = (args, sc.parts.tail).zipped map { "\\Q" + _ + "\\E" + _ } mkString "" (sc.parts.head + res).r }}
SIP-15: Value ClassesSó podem ter um parâmetro
O parâmetro deve ser um valOu seja, [T: Ordering](v: T) não é aceitoPode ser estendidas por traits
Se os mesmos estenderem Any ou AnyValNão podem definir igualdade ou hash code
Podem ser case classes!Igualdade e hash code são aplicadas sobre o
parâmetroSão efetivamente “final”Em um escopo local, são removidas por otimizaçãoSe escapam do escopo, são boxed
SIP-16: MacrosCompiladores grandes são de difícil
manutençãoPressão contra adição de funcionalidades
Plugins do compilador resolvem......mas são difíceis de manter em sincronia
Possível solução: Macros“Macros? Ugh!” – trauma do C/C++!
Novidade: scala.reflectionMacros saem quase de graça!
SIP-16: MacrosScala CATs!
Compile-time AST Transformations Abstract Syntax Tree
Inspirado pelas macros de NemerleQuatro tipos cogitados:
Typed macros – Somente este tipo está disponível!
Untyped macrosType (class/trait) macrosAnnotation macros
SIP-16: Macros// Typed macros
(1 to 5).foreach(println) ^ ^ | + Verificação de tipos + Macro executada + Nova verificação de tipos
SIP-16: Macros// Untyped macros
for {val i = 0; i < 10; i += 1} println(i)^ ^ | || + Tipo dos argumentos não é checado!+ Macro executada+ Verificação de tipos
SIP-16: Macros// Untyped macros – porque?
for {val i = 0; i < 10; i += 1} println(i) ^ ^ | “i” não existe neste escopo! + + “i” só existe neste escopo.
SIP-16: Macros// Type (class/trait) macros
class User extends DbTable(jdbcUrl, “t_user”) ^ + Macro
// Banco de dados é consultado durante// compilação para geração do corpo da// classe “User”
SIP-16: MacrosType macros são similares aos type providers
de F#
Só que mais. ;-)
Versão experimental de SLICK (ex-ScalaQuery) implementada com versão experimental de type macros
SIP-16: Macros// Macro annotations
@memoizedef fat(n: Int) = if (n > 0) n * fat(n – 1) else 1
// Macro aplicada ao elemento anotado,// seja ele classe, método, parâmetro, etc
SIP-16: MacrosSomente typed macros disponibilizadas...Experimentalmente...Atrás do flag –language:experimental.macros...Mas várias partes da biblioteca padrão já as estão
usando!Por outro lado, tornar macros fáceis não foi um dos
objetivos...De propósito...Trauma das “macros” do C/C++ muito difuso......mas as verdadeiras macros do C++ são os
templates!
SIP-16: MacrosVantagens de Typed Macros:
Relativamente simples de implementarAssinatura de método implementado com
macro não tem nenhuma diferença! Facilidade para testar
Higiene provida através de macro!Macros não higiênicas fáceis de criar
SIP-16: MacrosDesvantagens:
Limites no que é possívelCompilação em dois estágios
Não é possível compilar uma macro e usá-la em um único passo
Não-higienica por defaultQuem é do contra vai continuar achando ruim
SIP-16: Macrosobject Trimmer { def trim(s: String): String = macro trimImpl
import scala.reflect.makro.Context def trimImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = { import c.universe._ // see reflection
val Literal(Constant(untrimmed: String)) = s.tree val trimmed = untrimmed.lines.map(_.trim).mkString("\n")
c.Expr(Literal(Constant(trimmed))) }}
SIP-16: MacrosTipos de métodos dependentes de tipos:
def m(c: Context)(param: c.Expr[Any]): c.Expr[Any]
Opção –Ydependent-method-types em versões anteriores
Reflexão, reflexão e reflexão! “Uma vez que temos reflexão direito, macros
vem de graça!” – parafraseando Martin Odersky
SIP-17: Tipo DynamicProblema: a integração de Scala com outras
linguagens assume tipagem estáticaGrande quantidade de alternativas dinâmicas
na JVM!Solução: trait DynamicSimilar ao “missing method”Facilita integração com linguagens dinâmicas
na JVMMas tem outras utilidades...
SIP-17: Tipo Dynamicscala> class xmlPath(xml: scala.xml.Node) extends Dynamic { | def selectDynamic(path: String) = xml \\ path | }defined class xmlPath
scala> new xmlPath(<root><a><b><c/></b></a></root>).bres9: scala.xml.NodeSeq = NodeSeq(<b><c/></b>)
SIP-17: Tipo DynamicConversões:
Métodos convencionais:applyDynamic
Métodos com nome de parâmetros:applyDynamicNamed
Atribuições (setters):updateDynamic
Valores (getters):selectDynamic
Problemas:Algumas funcionalidades de Scala são de difícil
compreensãoOutras induzem a errosE algumas são experimentais
Mas são todas necessárias, por uma razão ou outra!
Solução: SIP-18
SIP-18: Modularização de Funcionalidades da Linguagem
Controla acesso a certas funcionalidadesUso das funcionalidades causa avisos
Mas podem se tornar erros em futuras versõesLiberação de uso através de:
flag de compilaçãovalor implícito no escopo
Liberação pode ser herdadaScalaDoc explica prós e contras de cada
funcionalidade
SIP-18: Modularização de Funcionalidades da Linguagem
Funcionalidades contenciosasOperadores pós-fixadosChamada de métodos implementadas via reflexãoConversões de tipo implícitasHigher kinded typesExistenciais
Exceto aqueles que equivalem a Java wildcard typesTipo Dynamic
Funcionalidades experimentaisMacros
SIP-18: Modularização de Funcionalidades da Linguagem
SIP-18: Modularização de Funcionalidades da Linguagem// Notação de operador pós-fixado
scala> "abc" lengthwarning: there were 1 feature warnings; re-run with -feature for detailsres0: Int = 3
SIP-18: Modularização de Funcionalidades da Linguagem// Notação de operador pós-fixado, com –feature
scala> "abc" length<console>:8: warning: postfix operator length should be enabledby making the implicit value language.postfixOps visible.This can be achieved by adding the import clause 'import language.postfixOps'or by setting the compiler option -language:postfixOps.See the Scala docs for value scala.language.postfixOps for a discussionwhy the feature should be explicitly enabled. "abc" length ^res0: Int = 3
SIP-18: Modularização de Funcionalidades da Linguagem// Chamada de métodos implementadas via reflexão
scala> val x = new AnyRef { def hello = println("world") }x: Object{def hello: Unit} = $anon$1@7d628303
scala> x.hello<console>:10: warning: reflective access of structural type member method hello should be enabledby making the implicit value language.reflectiveCalls visible.This can be achieved by adding the import clause 'import language.reflectiveCalls'or by setting the compiler option -language:reflectiveCalls.See the Scala docs for value scala.language.reflectiveCalls for a discussionwhy the feature should be explicitly enabled. x.hello ^world
SIP-18: Modularização de Funcionalidades da Linguagem// Conversões Implícitas
scala> implicit def f(s: String): Int = Predef.augmentString(s).toInt<console>:8: warning: implicit conversion method f should be enabledby making the implicit value language.implicitConversions visible.This can be achieved by adding the import clause 'import language.implicitConversions'or by setting the compiler option -language:implicitConversions.See the Scala docs for value scala.language.implicitConversions for a discussionwhy the feature should be explicitly enabled. implicit def f(s: String): Int = Predef.augmentString(s).toInt ^f: (s: String)Int
A funcionalidade limitada são as conversões implícitas
Outros usos de implicits continuam liberados (e incentivados!)
E conversões implícitas através de classes implícitas também
SIP-18: Modularização de Funcionalidades da Linguagem
SIP-18: Modularização de Funcionalidades da Linguagem// Higher Kinded Types
scala> class Monad[M[_]]<console>:9: warning: higher-kinded type should be enabledby making the implicit value language.higherKinds visible.This can be achieved by adding the import clause 'import language.higherKinds'or by setting the compiler option -language:higherKinds.See the Scala docs for value scala.language.higherKinds for a discussionwhy the feature should be explicitly enabled. class Monad[M[_]] ^defined class Monad
SIP-18: Modularização de Funcionalidades da Linguagem// Existenciais
scala> val l: List[ T forSome { type T }] = List(1)<console>:7: warning: the existential type T forSome { type T }, which cannot be expressed by wildcards, should be enabledby making the implicit value language.existentials visible.This can be achieved by adding the import clause 'import language.existentials'or by setting the compiler option -language:existentials.See the Scala docs for value scala.language.existentials for a discussionwhy the feature should be explicitly enabled. val l: List[ T forSome { type T }] = List(1) ^l: List[T forSome { type T }] = List(1)
SIP-18: Modularização de Funcionalidades da Linguagem// Tipo Dynamic
TODO
SIP-18: Modularização de Funcionalidades da Linguagem// Macros
scala> def g(d: Any): Any = macro f<console>:12: error: macro definition needs to be enabledby making the implicit value language.experimental.macros visible.This can be achieved by adding the import clause 'import language.experimental.macros'or by setting the compiler option -language:experimental.macros.See the Scala docs for value scala.language.experimental.macros for a discussionwhy the feature needs to be explicitly enabled. def g(d: Any): Any = macro f ^
scala.reflectPermitem explorar a estrutura de um
programa,e interagir com esta estrutura
Wiki: reflexão ocorre em tempo de execuçãoScala: você usa a mesma biblioteca em tempo
de compilação, com macrosNoções fundamentais:
Bibliotecas de reflexão e UniversosNomes, símbolos, tipos, árvoresMirrors
scala.reflect – Universos
Fonte: Scala Reflection Pre-SIP
scala.reflect – UniversosContém uma série de elementos interligados
que, juntos, formam os componentes fundamentais da reflexãoSymbolTreeNameetc...
Uso de path dependent types para associar tipos aos universos dos quais se originaram
scala.reflect – UniversosConstruído com o “cake pattern” em camadas
com diferentes graus de detalhes:Base:
Conceito fundamentais Identidade, e pouco mais
JavaUniverse Manipulação baseada nas facilidades de reflexão provida
pela JVM, melhorada com informações de ScalaMakro
Manipulação em tempo de compilação Universo do compilador, mas com uma API mais restrita
Outros: Compilador
scala.reflect – Tipos Fundamentais
Universo
Name
Symbol
Type
Tree
Position
AnnotationInfo
FlagSet
scala.reflect – Name
Name
TermName
TypeName
scala.reflect – NameScala possui dois espaços de nome:
TiposValores (Term)
Name associa uma string a um desses dois espaços
Name também permite converter entre a representação na linguagem, e a representação nos class files
scala.reflect – Symbol
Symbol
Type
Symbol Type ...
owner
Symbol
Name
TermName
TypeName
scala.reflect – SymbolTodas definições estão associadas a símbolos
ClassesMétodosParâmetrosVariáveisSe você deu um nome, tem um símboloSe você não deu um nome, mas chama de
“anônimo”, tem um símbolo tambémMutável no compilador, imutável em tempo
de execução
scala.reflect – TypeRepresenta a estrutura associada a um tipo:
Membros das classesParâmetros e tipo de retorno de um métodoetc
Formado por case classes imutáveisManipulado através de pattern matching
scala.reflect – Tipos e Símbolosscala> import scala.reflect.runtime.universe._import scala.reflect.runtime.universe._
scala> typeOf[List[Int]]res0: reflect.runtime.universe.Type = List[Int]
scala> res0.member(newTermName("head"))res1: reflect.runtime.universe.Symbol = method head
scala> res1.typeSignatureres2: reflect.runtime.universe.Type = => A
scala> res1.typeSignatureIn(res0)res3: reflect.runtime.universe.Type = => Int
scala.reflect – Tipos e Símbolosdef intMethods[T : TypeTag](v: T) = { val IntType = typeOf[Int] val vType = typeOf[T] val methods = vType.nonPrivateMembers.collect { case m: MethodSymbol => m -> m.typeSignatureIn(vType) } methods collect { case (m, mt @ NullaryMethodType(IntType)) => m -> mt case (m, mt @ MethodType(_, IntType)) => m -> mt case (m, mt @ PolyType(_, MethodType(_, IntType))) => m -> mt }}
scala.reflect – Tipos e Símbolosdef intMethods[T : TypeTag](v: T) = { val IntType = typeOf[Int] val vType = typeOf[T] val methods = vType.nonPrivateMembers.collect { case m: MethodSymbol => m -> m.typeSignatureIn(vType) } methods collect { case (m, mt @ NullaryMethodType(IntType)) => m -> mt case (m, mt @ MethodType(_, IntType)) => m -> mt case (m, mt @ PolyType(_, MethodType(_, IntType))) => m -> mt }}
scala.reflect – Tipos e Símbolos// Na verdade, você precisa disso:
case (m, mt @ NullaryMethodType(tpe)) if tpe =:= IntType =>
scala.reflect – Tree
Tree
children
Tree Tree ... Tree
Type Position
Symbol
TypTree TermTree
scala.reflect – TreeSão a representação interna do compilador
do código fonteImutável, formado por case classesEssencial ao se lidar com macrosUsado para annotated typed na biblioteca
básica
scala.reflect – Treescala> import scala.tools.reflect.ToolBoximport scala.tools.reflect.ToolBox scala> import scala.reflect.runtime.{currentMirror => m}import scala.reflect.runtime.{currentMirror=>m} scala> val tb = m.mkToolBox()tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@5bbdee69 scala> val tree = tb.parseExpr("1 to 3 map (_+1)")tree: tb.u.Tree = 1.to(3).map(((x$1) => x$1.$plus(1))) scala> val eval = tb.runExpr(tree)eval: Any = Vector(2, 3, 4)
scala.reflect – Treescala> import scala.reflect.runtime.universe._import scala.reflect.runtime.universe._
scala> showRaw(reify({ def f(x: Int, y: Int) = x + y }).tree)res4: String = Block(List(DefDef(Modifiers(), newTermName("f"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("x"), Ident(scala.Int), EmptyTree), ValDef(Modifiers(PARAM), newTermName("y"), Ident(scala.Int), EmptyTree))), TypeTree(), Apply(Select(Ident(newTermName("x")), newTermName("$plus")), List(Ident(newTermName("y")))))), Literal(Constant(())))
scala.reflect – Mirror
InstanceMirror
ClassMirror FieldMirror MethodMirror
ModuleMirror
ClassMirror
MethodMirror
(constructors)
scala.reflect – MirrorMirrors permitem manipulação de instâncias
e classes em tempo de execuçãoCada Universe pode ter um ou mais mirrorsCada mirror está associado a um class loaderClasses de mesmo nome podem existir
carregadas por class loaders distintosMirrors permitem manipulação baseada na
linguagem Scala, e não em sua implementação na JVM
scala.reflect – Mirrorval obj = "String"val objClass = obj.getClassval classClassLoader = objClass.getClassLoaderval classLoaderMirror = runtimeMirror(classClassLoader)val classSymbol = classLoaderMirror.classSymbol(objClass)val classType = classSymbol.typeSignatureval methodName = newTermName("length")val methodSymbol = classType.member(methodName).asMethodSymbolval instanceMirror = classLoaderMirror.reflect(obj)val methodMirror = instanceMirror.reflectMethod(methodSymbol)methodMirror.apply() // == (obj.length: Any)
Atores e Akka???A biblioteca padrão deixará de existir
Substituída pelo AkkaQuando???
A biblioteca Akka fará parte da distribuição 2.10Somente binários – código fonte permanece
separadoSerá disponibilizado um guia de migraçãoA biblioteca padrão virá com um “kit” para
facilitar a migraçãoPara que serve?
O futuro distante
Especulaçõesuntyped macros
for { val x = 0; x < 10; x += 1 } println(x)
macro typesclass X extends MacroClassY(parm)
macro annotations@memoize def fat(n: Int) = if (n > 0) n * fat(n -1) else 1
effect systemintegração de abstract types e type parameters.pré-processador (DOA!)