Union Types and Literal Singleton Types in Scala (and Typescript)
-
Upload
joost-de-vries -
Category
Technology
-
view
259 -
download
1
Transcript of Union Types and Literal Singleton Types in Scala (and Typescript)
joost@de-vries․namejoost-de-vriesjouke
UNIONTYPES&
LITERALSINGLETONTYPES
INGZandkasteel-Amsterdam
THREEACTS1. Whatarethey?Whyaretheyuseful?
2. HowtousetheminScalarightnow
3. UsingtheminDotty
①UNIONTYPES&
LITERALSINGLETONTYPESWhatarethey?
Whyaretheyuseful?
LITERALSINGLETONTYPES
Weknowsingletontypes:everyscalasingletonhasatype
objectS{
}
defg(s:S.type)=s//g:(s:S.type)S$
Asingletontypeisatypewithjustoneinstance
LITERALSINGLETONTYPES
Butwhatwe'dliketoexpressisliteralsintypes.ForinstanceinSpire
forAll{x:Ranged[Int,1,100]=>valn:Int=x.value//guaranteedtobe1to100}
LITERALSINGLETONTYPESAndinScala.js
Thesearesomeofthemotivationsmentionedin
traitHTMLCanvasElementextendsHTMLElement{defgetContext(contextId:String):AnydefgetContext(contextId:"2d"):CanvasRenderingContext2D}
valanyContext=canvas.getContext("webgl")valcontext2D=canvas.getConttext("2d")
SIP-42
UNIONTYPES
It'sorfortypes
Terminologyfromsettheory
INTERSECTIONTYPES
It'sandfortypes
TRANSLATION
And ⇒ Or
∧ ⇒ ∨
Conjunction ⇒ Disjunction
Intersection ⇒ Union
Co-product ⇒ Tuple/Product/HList
Canbeconfusing
INTERSECTIONTYPESWealmosthaveintersectiontypesinScala
Usuallyusedformixins
ButAwithBdoesn'tequalBwithA
valloggablePerson=newPersonwithLoggable()
UNIONTYPESAREUSEFUL
It'sEither[A,B]
foranynroftypes
withoutboxing
/***If'padding'isastring,then'padding'isappendedtotheleftside.*If'padding'isanumber,thenthatnumberofspacesisaddedtotheleftside.*/functionpadLeft(value:string,padding:string|number)={//...}padLeft("hello",true)//doesn'tcompile
UNIONTYPES
Eithercan'tdothat
interfaceBird{fly()layEggs()}
interfaceFish{swim()layEggs()}
functiongetSmallPet():Fish|Bird{/*...*/}
letpet=getSmallPet()pet.layEggs()//okay//pet.swim()doesn'tcompile
USEUNIONTYPESFORNONNULLABLETYPES
letfoo:string=null//Error!
letfoo:string|null=null//Okay!
UsingthestrictNullCheckcompileroption
UNIONOFLITERALTYPES
Whatanawesomeway
toexpressenumerations!
typeDigit=0|1|2|3|4|5|6|7|8|9;letnums:Digit[]=[1,2,4,8];
nums.push(16)//Doesn'tcompile
②UNIONTYPES&
LITERALSINGLETONTYPESHowtousetheminScalarightnow
UNIONTYPESINSCALARIGHTNOW
PROGRAMMINGISLIKELOGICif it is thursday there's a scala meetingif there's a scala meeting the term 'monad' will come upit is thursday-------------------------------------------------------the term 'monad' will come up
PROGRAMMINGISLIKELOGICit is thursday → there's a scala meetingthere's a scala meeting → the term 'monad' will come upit is thursday-------------------------------------------------------the term 'monad' will come up
PROGRAMMINGISLIKELOGICThursday → ScalaMeetingScalaMeeting → MonadThursday-------------------------------------------------------Monad
PROGRAMMINGISLIKELOGIC
valf:Thursday⇒ScalaMeetingvalg:ScalaMeeting⇒Monadvalt:Thursday
valm:Monad=g(f(t))
Theimplementationofthefunctionistheproofofitstype
INLOGICWecancreateoroutofand,not
AorB⇔not(notAandnotB)
INLOGICWecancreateoroutofand,not
A⋁B⇔¬(¬A⋀¬B)
SCALATOLOGIC(AwithB)<:A (A∧B)⇒A
(AwithB)<:B (A∧B)⇒B
A<:(A∨B) A⇒(A∨B)B<:(A∨B) B⇒(A∨B)
CREATINGORFROMAND,NOT
(A∨B)⇔¬(¬A∧¬B)becomes
(A∨B)=:=¬[¬[A]with¬[B]]
Sowheredowegetnot?
UNIONTYPESIN3LINESOFCODE
IsMilesSabincoolorwhat?
AninstanceofA<:<BwitnessesthatAisasubtypeofB
type¬[A]=A=>Nothing
type∨[T,U]=¬[¬[T]with¬[U]]
type¬¬[A]=¬[¬[A]]
implicitly[¬¬[Int]<:<(Int∨String)]//res0:<:<[¬¬[Int],∨[Int,String]]=<function1>
implicitly[¬¬[Double]<:<(Int∨String)]//error:Cannotprovethat¬¬[Double]<:<∨[Int,String].
LET'SUSEOURUNIONTYPE
defpadLeft[T](value:String,padding:T)(implicitev:¬¬[T]<:<(Int∨String))="somestring"
padLeft("hello",3)//compiles
//padLeft("hello",true)doesn'tcompile://error:CannotprovethatTest5.¬[Test5.¬[Boolean']]<:<Test5.∨[Int,String].//padLeft("hello",true)
UNIONTYPESIN3LINESOFCODE
PuttheevidenceinapathdependenttypeλspecifictoourtypesTandU
type|∨|[T,U]={typeλ[X]=¬¬[X]<:<(T∨U)}
defpadLeft2[T](value:String,padding:T)(implicitev:(Int|∨|String)#λ[T])="somestring"
USETHEIMPLEMENTATIONINSHAPELESS
UniontypesarecalledCoproductsinShapeless
Literaltypes(peanonumbers)areusedinSizedcollections
③UNIONTYPES&
LITERALSINGLETONTYPESUsingtheminDotty
UNIONTYPES
Whatwewanttoachieve
/***If'padding'isastring,then'padding'isappendedtotheleftside.*If'padding'isanumber,thenthatnumberofspacesisaddedtotheleftside.*/functionpadLeft(value:string,padding:string|number)={//...}padLeft("hello",true)//doesn'tcompile
UNIONTYPESINDOTTY/***If'padding'isastring,then'padding'isappendedtotheleftside.*If'padding'isanumber,thenthatnumberofspacesisaddedtotheleftside.*/defpadLeft(value:String,padding:String|Int)={//...}padLeft("hello",true)
//error:typemismatch://found:Boolean(true)//required:String|Int//padLeft("hello",true)//^
Cool!
UNIONTYPESINDOTTYclassBird(){deffly()={}deflayEggs()={}}
classFish(){defswim()={}deflayEggs()={}}
defgetSmallPet()=if(newRandom().nextBoolean)newFish()elsenewBird()
valp=getSmallPet()
p.layEggs()error:valuelayEggsisnotamemberofObject(p)p.layEggs()^
Huh?
UNIONTYPESINDOTTYimportdotty.language.keepUnions
classBird(){deffly()={}deflayEggs()={}}
classFish(){defswim()={}deflayEggs()={}}
defgetSmallPet()=if(newRandom().nextBoolean)newFish()elsenewBird()
valp=getSmallPet()
p.layEggs()//compiles Becauseofperformance
oflargenrsofunionedtypes
UNIONTYPESPLUSSINGLETONTYPESINDOTTY
objectMondayobjectTuesday//...
typeWeekday=Monday.type|Tuesday.type|Wednesday.type|Thursday.type|Friday.typetypeWeekend=Saturday.type|Sunday.typetypeAnyDay=Weekday|Weekend
println("Mondayisweekday:"+Monday.isInstanceOf[Weekday])println("Saturdayisweekend:"+Saturday.isInstanceOf[Weekend])println("Sundayisweekday:"+Sunday.isInstanceOf[Weekday])
(Monday:AnyDay)match{case_:Weekend=>println("shouldn'tmatch")}
Worksagainsince7daysago
UNIONTYPESPLUSSINGLETONTYPESINDOTTY
Bug!
typeWeekday="Monday"|"Tuesday"|"Wednesday"|"Thursday"|"Friday"typeWeekend="Saturday"|"Sunday"typeAnyDay=Weekday|Weekend
vald:Weekday="Sunday"//compiles?!
Currentlyunionsofliteraltypesarewidened
toStringinthiscase
UNIONTYPESPLUSSINGLETONTYPESINDOTTY
Sameproblem
typeDigit=0|1|2|3|4|5|6|7|8|9
defformat(ds:Seq[Digit])={}
format(Seq(4,9,13))//shouldn'tcompile
UNIONTYPESPLUSSINGLETONTYPESINDOTTY
DOTTYItreallyis,likethesitesays,prebeta
It'seasytotryoutwiththesbt-dottyplugin
Althoughtherearenosnapshotbuildsyet
But:syntaxhighlightingintheconsole!
Kleurtjes!
Fin