Scalaã®ãã¬ã¤ãã¯å®ã¯ãã¬ã¤ããããªããã ã®ãã¯ã¹ã¤ã³
ã¿ã¤ãã«ã¯é£ãã§ãã
ã¾ããããã£ã±ã«ç¨èªã®æ´çãããã¦ããã ãã¨ãããã§ããã¬ã¤ããã¯ãã·ã§ã«ãªï¼Nathanael Schärliï¼ãã2002å¹´é ã«çºè¡¨ããTraitsãããç¨ã®ã¨ã³ãã£ãã£ï¼traitï¼ãæããããã¯ã¹ã¤ã³(Mixin, mixin)ãã¯å¾æ¥ããããå®è£ ã®å¤éç¶æ¿æ¹æ³ã®ã²ã¨ã¤ãå ·ä½çã«ã¯ç¶æ¿æ©æ§ã使ã£ã¦ã¡ã½ãããå®ç¾©ããã¯ã©ã¹æ§ã¨ã³ãã£ãã£ï¼ã¯ã©ã¹ã§ãæ§ããªãï¼ãç¶æ¿ãã¹ã«å·®ãè¾¼ããã¨ã§å¯¾è±¡ã¨ãªãã¯ã©ã¹ã«ã¡ã½ããã追å ããæ©æ§ï¼ç¹å¥ãªæ©æ§ãè¦ããªãã¨ãã¯åãªãã¯ã©ã¹ã®éç¨æ¹æ³ï¼ããã®ã¨ãã«ç¨ããã¯ã©ã¹ãããã¯ã¯ã©ã¹æ§ã¨ã³ãã£ãã£ï¼ä¾ãã°Rubyãªãã¢ã¸ã¥ã¼ã«ã¨ãï¼ãæããã¨ã«ãã¾ãã
ãã¬ã¤ãããã®æ©æ§ã«ã¤ãã¦èª¬æãã¹ããã¨ã¯ããããããããã§ããã詳ããã¯ã·ã§ã«ãªãã®è«æï¼Traits: Composable Units of Behaviour ãªã©ï¼ãèªãã§ããã ãã¨ãã¦ãããã§ã¯å®è£ ã®å¤éç¶æ¿ã®ããã¿ã¨ãã¦èããå ´åã®ãã¯ã¹ã¤ã³æ©æ§ã¨ã®éãããå°ã ä¹±æ´ã§ããåç´ã«ããã¯ã¹ã¤ã³ã®ããªãã¢åãããã¬ã¤ãã®ããã©ããåãããã«çµããã¨ãå¯è½ã ã¨èãããã¨ã«ãã¾ãã
ä¾ãã°ãè¤æ°ã®ãã¯ã¹ã¤ã³M1ãM2ï¼ãã®ãã®ãããã«M0ãç¶æ¿ï¼ãåæã«ç¶æ¿ããå ´åããã¯ã¹ã¤ã³æ©æ§ã§ã¯ä½ããã®ã«ã¼ã«ã«å¾ã£ã¦ãã¯ã¹ã¤ã³ãé çªã«åã¹ï¼ãªãã¢åãï¼ã¦ããã®åã³ãç¶æ¿ãã¹ã«æ¿å ¥ãã¾ããPythonã§æ¸ãã¨ãããªæãã§ããããã
class B(object): def m(self): print "B", class C(B): def m0(self): print "C", self.m() C().m0() #=> C B
class M0(object): def m(self): print "M0", super(M0, self).m() class M1(M0): def m(self): print "M1", super(M1, self).m() class M2(M0): def m(self): print "M2", super(M2, self).m() class C(M1, M2, B): def m0(self): print "C", self.m() C().m0() #=> C M1 M2 M0 B
ãããããã¯ã¹ã¤ã³ã®æåã«å¯¾ãããã¬ã¤ãæ©æ§ã§ã¯åæã« use ãããã¬ã¤ãã¯ã¾ãããã©ããåãããã¾ãããã¬ã¤ãã¯ãã¨ããããã¡ã½ãããæãããã®ï¼éåï¼ã ã¨æã£ã¦ãã ãããåæã« use ãããè¤æ°ã®ãã¬ã¤ãã¯ããã£ããã°ããã¦ã²ã¨ã¤ã®ä»®æ³çãªãã¬ã¤ãã«ã¾ã¨ãããã¦ããã®å¾ãæ¹ãã¦ã¯ã©ã¹ã« use ãããï¼ãããã¯ã注å
¥ããããï¼ã¨èããã¨å°ãããããããã§ãããã®éãã¡ã½ããåã®è¡çªãè¦ã¤ããã°å®è¡æã«ã¨ã©ã¼ã«ãªã£ããã³ã³ãã¤ã«ã«å¤±æãã¾ããã¤ã¾ããå
ã® Python ã®ãã¯ã¹ã¤ã³ã®ä¾ã®ãããªã³ã¼ãã¯ãã¬ã¤ãã§ã¯ãã®ã¾ã¾ã§ã¯åãã¾ããã
å®éã«ã©ããªãã Squeak Smalltalk ã§è©¦ãã¦ã¿ã¾ãããã
次ã®ã³ã¼ãã¯ãå ã®ã³ã¼ãã®ãã¯ã¹ã¤ã³ã®ã¨ããããã¬ã¤ãã«ç½®ãæã㦠Squeak Smalltalk åãã«æ¸ãç´ãããã®ã§ããSqueak Smalltalk ã® IDE ã«ãã¾ã詳ãããªãã¦ããã èµ·åãã¦ã¯ã¼ã¯ã¹ãã¼ã¹ãªã©ã«è²¼ãä»ãã空è¡ã§éã¦ãããå¼ã²ã¨ã¤ã²ã¨ã¤ãé ã«é¸æãã¦ãã do it (alt/cmd + d)ããããfileIn (å ¨ä½ãé¸æãã¦ãã alt/cmd + shift + gããããã¯ãã®ã³ã¼ãã example.st ã«ä¿åãã¦ãã (FileStream fileNamed: 'example.st') fileIn ã do it ããçã )ãã¦å®è¡ã§ããã³ã¼ãã¨ãã¦è¨è¿°ãã¦ããã¾ããã¯ã©ã¹ãã©ã¦ã¶ã使ããªããããé常㮠Smalltalk ã®ã³ã¼ãã®æ¸ãæ¹ãå®è¡ã®ãããããã¯å¤ãã¾ããããã®ç¹ãçæãã ããã
ãªããåæ§ã®ãã¨ã¯ãããã¤ã³ã¹ãã¼ã«ã®「Smalltalk入門」ã§è©±é¡ã® Pharo Smalltalk ã§ã試ãã¾ãããPharo 1.4 ã«ã¯ #uses: ãç¡ãã®ã§èªåã§å¥éå®ç¾©ãã¦ãããã該å½ã¡ã½ããã使ç¨ãã¦ããå¼ããããããæ¸ãæããå¿ è¦ãããã¾ãï¼ã¡ãã£ã¨é·ãã§ãã B subclass: #C uses: T1-{#m}+T2 instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Traits-Examples'. ãªã©ã¨ãã¦è©¦ãã¦ã¿ã¦ãã ããï¼ã
Object subclass: #B instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Traits-Examples'. B compile: 'm Transcript space; show: #B; cr; endEntry'. B subclass: #C instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Traits-Examples'. C compile: 'm0 Transcript space; show: #C. self m'. Transcript open. C new m0. "=> C B "
Trait named: #T0 uses: {} category: 'Traits-Examples'. T0 compile: 'm Transcript space; show: #T0. super m'. Trait named: #T1 uses: T0 category: 'Traits-Examples'. T1 compile: 'm Transcript space; show: #T1. super m'. Trait named: #T2 uses: T0 category: 'Traits-Examples'. T2 compile: 'm Transcript space; show: #T2. super m'. C uses: T1 + T2. Transcript open. C new m0 "=> Error: A class or trait does not properly resolve a conflict between multiple traits it uses. "
ãã®ããã«è¡çªã®æ¤åºãåããã¨ã©ã¼ã«ãªã£ã¦ãã®ã¾ã¾ã§ã¯æå¾ã®åºåãã§ãã¾ããã
æ¤åºãããè¡çªãåé¿ããã«ã¯ãåå ã¨ãªã£ã¦ããã¡ã½ããã®ãã¡ã©ããã©ã®ãã¬ã¤ãããæé¤ãããã use ããã¨ãã«æ示çã«ãã¦ããå¿ è¦ãããã¾ãããã¨ãã°ãã¨ã©ã¼ãåºãæå¾ã®å¼ãå«ãä¸ã¤ã®å¼ã次ã®ãããªå¼ã«ç½®ãæããã¨æ£å¸¸ã«åä½ããããã¾ãï¼ãã®å ´åã¯ããã¬ã¤ãT1 ã®ã¡ã½ããm ãæé¤ãããã¨ã§ãçµæçã«ãã¬ã¤ãT2 ã® m ãæ®ãã¦ãã¾ãï¼ã
C uses: T1 - {#m} + T2. Transcript clear. C new m0 "=> C T2 B "
åºåçµæããã¯ã¹ã¤ã³ã®å ´åã¨ã¯éã£ã¦ãããã¨ã«æ°ä»ãããã§ããããããã®ããã«åºåãããã¨ã¾ã㧠T0 ã T1 ãã¨æé¤ããã¦æ©è½ãã¦ããªãããã«è¦ãã¾ãããå®éã«ã¯ãããªãã¨ã¯ããã¾ãããããã¾ã§ã¡ã½ãã m ã«ã¤ãã¦ã®ã¿ããã©ããåã®çµæãT2 ç±æ¥ã® m ã使ããã¦ããã¨ããã ãã®è©±ã§ããT0 ã T1 ãå¼ãç¶ã use ããã¦ãã¾ãã®ã§ãä¾ãã°ãT0 ã«ã¡ã½ããmT0ãT1 ã« mT1 ã追å ã§å®ç¾©ãã¦ããã°ããµã¤ãã«ããããã C ã®ã¤ã³ã¹ã¿ã³ã¹ããã³ã¼ã«ã§ãã¾ãã
T0 compile: 'mT0 Transcript space; show: #mT0'. T1 compile: 'mT1 Transcript space; show: #mT1'. C new mT0; mT1. "=> mT0 mT1 "
ããããæ¬æ¥ããã¬ã¤ãã«æå¾
ãããæåã§ãã
ã§ã¯ãScala ã®ãã¬ã¤ãã¯ã©ããã¨ããã¨ã話ã®æµãããããäºæ³ã¯å®¹æã«ã¤ãã¨æãã¾ããããããªãµãã«ãªãã¾ãã
trait TA { def m() : Unit } trait T0 extends TA { abstract override def m = { print("T0 ") super.m } } trait T1 extends T0 { abstract override def m = { print("T1 ") super.m } } trait T2 extends T0 { abstract override def m = { print("T2 ") super.m } } class B { def m = println("B") } class C1 extends B { def m0 = { print("C1 ") m } } class C2 extends B with T1 with T2 { override def m = super.m def m0 = { print("C2 ") m } } object Example extends App { (new C1).m0 //=> C1 B (new C2).m0 //=> C2 T2 T1 T0 B }
Python ã¨åããã¯ã¹ã¤ã³ã®æåã§ããããã¨ãããã«ã宣è¨æã«ä½ã extends ãã¦ããªã T0 ã® m ãã㯠super.m ãã³ã¼ã«ã§ããªãããããã¬ã¤ãã使ã£ãå¾è
ã®åºåã§ã¯ B ãæãã¦ãã¾ãã
追è¨ï¼B ã® m ã T0 ã® m ãã super.m ã§ã³ã¼ã«åºæ¥ãªã件㯠abstract override 修飾åã¨æ½è±¡ãã¬ã¤ããä¸æ®µåã¾ããã¨ã§å®ç¾ã§ããããã§ãã
@kmizu æãã¦ããã ããabstract overrideã§ã件ã®T0ã® m ãããå°æ¥ç¶æ¿ãã¹ã®ä¸æµã«æ¥ãBã®mãsuper.mã¨ãã¦å¼ã¹ãããªã¨æã£ãã®ã§ããããã¯ãï¼å½ç¶ã§ããï¼AnyRefã«ã¯mãç¡ãã¨å±ããã¾ããBãäºãç¶æ¿ãã以å¤ã§ä½ãå®ç¾æ¹æ³ã¯ããã¾ããï¼
— sumim (@sumim) 2013å¹´3æ7æ¥
@sumim traitT{ def m; } ã¨å®ç¾©ãã¦ã trait T0 extends T { abstract override def m = { println("T0"); super.m } ã§æ¸ããã®ã§ã¯ãªããã¨æãã¾ã(確ããã¦ã¾ãããããã¾ãã)ã
— Kota Mizushimaãã (@kmizu) 2013å¹´3æ8æ¥
REPL ã® :power ã¢ã¼ãã§ç¢ºèªããã¨ãPython ã®ã¨ãã¨åæ§ã«ãC2 ã®ç¶æ¿ãã¹ã® T0 ã®ããä¸æµã« B ããã¡ãã¨æ¿å
¥ããã¦ãããã¨ãåããã¾ãï¼ãªããå
ã®å®è¡ã®çµæ㨠T1 T2 ãå
¥ãããã£ã¦ãã¾ã£ã¦ãã¾ãã???ï¼ã
追è¨ï¼ ãã®ä»¶ã@kmizu ãããã次ã®ãããªãææãããã ãã¾ããããããã¨ããããã¾ãã
@sumim 件ã®ãã¬ã¤ãã®è¨äºã§ãããä»ã®é¨åã¯ããã¨ãã¦ãREPLã®:powerã¢ã¼ãã§ç¢ºèªãã¦ãã®ã¯ãsub-typeé¢ä¿ã§ãã£ã¦ãclass linearlizationã®çµæã§ã¯ãªãã®ã§ãããã§å½ç¶ãã¨ã
— Kota Mizushimaãã (@kmizu) 2013å¹´3æ7æ¥
Scalaã®Class Linerizationã®ä»æ§ã«ã¤ãã¦ã¯ã http://www.scala-lang.org/docu/files/ScalaReference.pdf ã® p.56 ã«è¨è¼ãããã®ã§ããã£ã¡ãåç §ãããã®ãè¯ããã¨ãREPLã®power modeã§ã¯Class Linearizationã®çµæã¯ï¼ç°¡åã«ã¯ï¼åããªãã¨æãã¾ãã
— Kota Mizushimaãã (@kmizu) 2013å¹´3æ7æ¥
scala> :power ** Power User mode enabled - BEEP WHIR GYVE ** ** :phase has been set to 'typer'. ** ** scala.tools.nsc._ has been imported ** ** global._, definitions._ also imported ** ** Try :help, :vals, power.<tab> ** scala> intp.types("C2").tpe.baseTypeSeq.toList res1: List[$r.intp.global.Type] = List(C2, T1, T2, T0, B, Object, Any)
ã ããä½ã ï¼ãªããæå¥ãããã®ãï¼ã¨ãã¤ã£ããããããããã¨å°ãã¾ãããScala ã®ãã¬ã¤ãã¯ãã¬ã¤ããããªãããã·ã§ã«ãªãã®ãã¬ã¤ãã«ã¤ãã¦ã»ã¨ãã©ç¥ããªãã¦ãåé¡ãªãããã㨠Scala ã®ãã¬ã¤ãã®æåãåæã«ã·ã§ã«ãªãã®ãã¬ã¤ãã®èª¬æãèªãã¨æ··ä¹±ããããæ°ãã¤ãã¦ãã¨ãã£ãèå©å¿ããæ¸ãã¦ã¿ã¾ããã
追è¨ï¼
PHP ã 5.4.0 ããã·ã§ã«ãªãã®ãã¬ã¤ãããµãã¼ããã¦ãã¾ãã®ã§ãåæ§ã®ãµã³ãã«ã³ã¼ããæ¸ãã¦ã¿ã¾ãããå½ããåã§ãã Squeak Smalltalk ã®ãã¬ã¤ãã¨åãæåããã¾ãã
<?php trait T0 { public function m() { echo "T0 "; parent::m(); } } trait T1 { use T0; public function m() { echo "T1 "; parent::m(); } } trait T2 { use T0; public function m() { echo "T2 "; parent::m(); } } class B { public function m() { echo "B\n"; } } class C0 extends B { public function m0() { echo "C0 "; $this->m(); } } /* class C1 extends B { use T1, T2; //=> Fatal error: Trait method m has not been applied, because there are collisions with other trait methods public function m0() { echo "C1 "; $this->m(); } } // */ class C2 extends B { use T1, T2 { T2::m insteadof T1; } public function m0() { echo "C2 "; $this->m(); } } (new C0())->m0(); //=> C0 B (new C2())->m0(); //=> C2 T2 B