ãã¼ããstructural subtypingã¨ããã¯ã¿ã¤ãã³ã°ã¯åããã®ãªãã ãããã
— Yukihiro Matsumoto (@yukihiro_matz) 2016å¹´9æ8æ¥
https://t.co/5Rv86piThC
— INADA Naoki (@methane) 2016å¹´9æ8æ¥
wikipediaã«ããã¨ä¼¼ã¦éãªãç©ã®ããã§ããã https://t.co/VwIg39h5M0
ãã®è©±é¡ã«ã¤ãã¦è£è¶³ãã¦ããã¾ãããªããåã¯TAPLè±è½çµãªã®ã§ãã¾ãæ£ç¢ºæ§ã¯æå¾ ããªãã§ãã ããã
èæ¯
Ruby Kaigi 㧠Matz ã Ruby3 ã«åãã¦èãä¸ã®éçåã«ã¤ãã¦è©±ãããããã§ãã
å°ãåããã Python ã§ã Guido ã Dropbox ã§ã®å¤§éã®ã³ã¼ããã¼ã¹ãæ¹åãã¦ããããã« type hinting ãã»ããã¨ãããã¨ã§ PEP 484 ãå§ãã¾ããã
ããã§ã¯ã Java ãªã©ãæ¡ç¨ãã¦ããä¸çªããç¥ããã nominal subtyping, Go ãªã©ãæ¡ç¨ãã¦ãã structural subtyping, Python ã Ruby ã® duck typing, ãã㦠PEP 484 ãæ¡ç¨ãã Gradual Typing ã«ã¤ãã¦ãéããããããã«ç´¹ä»ãã¦ããã¾ãã
Nominal Subtyping
ã¾ãã¯æ¬¡ã®ã³ã¼ããè¦ã¦ãã ããã
interface IFoo { void Foo(String s); } class Foo implements IFoo { public void Foo(String s) {} } class Main { public static void main(String[] args) { IFoo f = new Foo(); f.Foo("hello"); } }
IFoo f = new Foo()
ã§ã¯ã IFoo åã®å¤æ° f ã宣è¨ãã Foo åã®ã¤ã³ã¹ã¿ã³ã¹ã§åæåãã¦ãã¾ãã
éçã«ï¼å®è¡ããªãã¦ãï¼å¤æ°ã«åãä»ãã¦ããã®ã§ãããã¯éçåä»ãã§ãã
IFoo åã®å¤æ°ã«ã Foo åã®ã¤ã³ã¹ã¿ã³ã¹ãä»£å ¥ãã¦ãã¾ããããã㯠Foo ã IFoo ã®ãµãã¿ã¤ãã ããã§ããï¼ã¡ãªã¿ã«ãµãã¿ã¤ãã®éã¯ã¹ã¼ãã¼ã¿ã¤ãã§ããï¼
ãµãã¿ã¤ãã¯ãã¹ã¼ãã¼ã¿ã¤ããå®ç¾©ãã¦ããAPIããã¹ã¦æä¾ãã¦ããå¿
è¦ãããã¾ããä¾ãã°ãã¹ã¼ãã¼ã¿ã¤ãã Foo(string) ã¨ããã¡ã½ãããå®ç¾©ãã¦ãããªãããµãã¿ã¤ãããã®ã¡ã½ãããæä¾ããªããã°ãªãã¾ããã
ã¹ã¼ãã¼ã¿ã¤ãã«å¯¾ãã¦å¯è½ãªæä½ããã¹ã¦ãµãã¿ã¤ãã«å¯¾ãã¦ãå¯è½ãªã®ã§ãã¹ã¼ãã¼ã¿ã¤ãã®åã®å¤æ°ã«ãµãã¿ã¤ãã®å¤ã代å
¥ãã¦ãã¹ã¼ãã¼ã¿ã¤ãã¨åãããã«æä½ã§ãããã¨ãä¿è¨¼ããã¾ããã¤ã¾ãã f.Foo("hello")
ã¯ã³ã³ãã¤ã«æã«å®å
¨æ§ãæ¤è¨¼ãããå®è¡æã« f
ã Foo(String)
ã¨ããã¡ã½ãããæã£ã¦ãªãã¨ããã¨ã©ã¼ã¯èµ·ããã¾ããã
ãã¦ãããã¾ã§ã®èª¬æã¯éçåä»ã㨠subtyping ã«ã¤ãã¦ã§ãããã§ã¯ nominal subtyping ã® nominal ã¨ã¯ä½ã§ããããï¼
ããã¯ã Foo implements IFoo
ã®ããã«ããµãã¿ã¤ãé¢ä¿ã宣è¨ã«ãã£ã¦å®ç¾©ããã¨ããæå³ã§ããããã¦ã nominal subtyping ã¨å¯¾ã«ãªãã®ã structural subtyping ã§ãã
Structural Subtyping (æ§é çé¨åå)
Nominal Subtyping ã implements ã extends ã¨ãã£ã宣è¨ã«ããé¨ååé¢ä¿ãæãç«ã£ã¦ããã®ã«å¯¾ãã¦ã Structural Subtyping ã§ã¯æ§é ã«ãã£ã¦é¨ååé¢ä¿ãæãç«ã¡ã¾ãã次ã®ä¾ãè¦ã¦ãã ããã
package main import ( "fmt" "io" ) type Reader interface { Read(buf []byte) (int, error) } type StringReader struct { s string } func NewStringReader(s string) *StringReader { return &StringReader{s} } func (r *StringReader) Read(buf []byte) (int, error) { l := len(r.s) if len(buf) < l { copy(buf, r.s) r.s = r.s[len(buf):] return len(buf), nil } copy(buf[:l], r.s) r.s = "" return l, io.EOF } func ReadPacket(r Reader) ([]byte, error) { header := make([]byte, 1) if _, err := r.Read(header); err != nil { return nil, err } l := int(header[0]) data := make([]byte, l) n, err := r.Read(data) return data[:n], err } func main() { r := NewStringReader("\x03foo") packet, _ := ReadPacket(r) fmt.Printf("%s\n", packet) }
StringReader å㯠Reader åãæ示çã«ç¶æ¿ãã¦ãã¾ãããã ReadPacket(r Reader) ã« *StringReader
åã®å¤ã渡ãã¦ãã¾ãã
Go ã®ã³ã³ãã¤ã©ã¯ã *StringReader
ã Reader
ã¤ã³ã¿ã¼ãã§ã¼ã¹ã宣è¨ãã¦ããã¡ã½ãããå
¨é¨å®ç¾©ãã¦ããã®ã§ããµãã¿ã¤ãã ã¨å¤æãã¦ãã¾ãããããæ§é ã«ããé¨ååã§ãã
Structural Subtyping ã® Nominal Subtyping ã«å¯¾ããã¡ãªãããèãã¦ã¿ã¾ãããã
ä»åæ¸ãããã£ãé¢æ° ReadPacket(r Reader)
ããæ¬å½ã¯ os.File
åãããã±ãããèªã¿è¾¼ãããã®é¢æ°ã§ã *StringReader
ã¯åã« ReadPacket ããã¹ãããããã®ã¢ãã¯ã ã£ãã¨ãã¾ãã
ãã os.File
ãä½ãã¤ã³ã¿ã¼ãã§ã¤ã¹ãç¶æ¿ãã¦ããªãã£ãã¨ãããã nominal typing ã§ã¯ã ReadPacket() ã®å¼æ°ã®åãã os.File ã¨ã¢ãã¯ã®ä¸¡æ¹ãç´æ¥åãåããããã«å®ç¾©ãããã¨ãã§ãã¾ãããèªå㧠os.File ãã©ããããã¯ã©ã¹ãä½ã£ã¦ Reader ã¤ã³ã¿ã¼ãã§ã¤ã¹ãç¶æ¿ããªãã¨è¡ããªãã®ã§é¢åã§ãã
ã¾ãã os.File
ã Read()
, Write()
, Close()
, Seek()
ãå®ç¾©ããã¤ã³ã¿ã¼ãã§ã¤ã¹ãå®è£
ãã¦ããå ´åã ReadPacket()
㯠Read()
ãã使ã£ã¦ããªãã®ã«ã *StringReader
ã¯3ã¤ã®ä½¿ã£ã¦ãªãã¡ã½ããã®ããã¼å®è£
ãããªãã¨ããã¾ããã§ããã
æ§é çé¨ååã¯ããã®ããã«å®éã«å©ç¨ãã¦ããã¡ã½ããã ããå®ç¾©ããã¹ã¼ãã¼ã¿ã¤ããå¾ä»ãã§ããã®ãé åã§ãã ã©ã¤ãã©ãªãæä¾ãã人ããå®è£ ãã¦ããåãä¸ã¤ã ããªã®ã«ã¦ã¼ã¶ã¼ãã¢ãã¯ãå®ç¾©ããããããããã«ã¤ã³ã¿ã¼ãã§ã¤ã¹ãä½ããªãã¦ãããªãã®ã§ãã©ã¤ãã©ãªã®APIã®è¦éãããããªãã¨ãã£ãã¡ãªãããããã¾ãã
Duck Typing
duck typing ã¯åçåä»ãè¨èªã«ããããã¨ãããããã£ã¦ã¿ã¦ã¨ã©ã¼ç¡ãåããããªãã±ã¼ãã¨ããåã·ã¹ãã ã§ããï¼ã¨ãããããã¯åã·ã¹ãã ãªã®ãï¼ï¼
次ã®ã³ã¼ããè¦ã¦ãã ããã
def read_packet(s): n = s.recv(1)[0] return s.recv(n)
ãã®ã³ã¼ãã¯ãã½ã±ããã®ãããªãªãã¸ã§ã¯ããå¼æ°ã«åããã¨ãæå¾
ãã¦ãã¾ãããã®ãªãã¸ã§ã¯ã㯠.recv(int)
ã¨ããã¡ã½ãããå®è£
ãã¦ãã¦ããã¤ãåãè¿ããã¨ãæå¾
ãã¦ãã¾ãããã¤ãåã«å¯¾ã㦠[0] ããã¨ãã®æ´æ°å¤ãåããã¾ã s.recv(int)
ãå¼ã³åºãã¦ããã®æ»ãå¤ã®ãã¤ãåãè¿ããã¨ããæ³å®ã§ãã
ãã®ã³ã¼ãã¯ã次ã®ããã«ãã¦å¼ã³åºãã¦ãã¨ã©ã¼ç¡ãå®è¡ãããã¨ãã§ãã¾ãã
class S: def recv(self, x): return [x] print(read_packet(S())) # => [1]
æ»ãå¤ã®å㯠bytes ãæå¾ ãã¦ããã®ã«ãé åãè¿ã£ã¦ãã¾ããããã§ããã¨ã©ã¼ãªãå®è¡ã§ãããã ãããããã§OKã¨ããã®ã duck typing ã§ãã å©ç¨è ã®ã¡ã³ã¿ã«ã¢ãã«ã¨ãã¦ã¯ã ã¤ã³ã¿ã¼ãã§ã¤ã¹ã®å®ç¾©ãçç¥ãã structural subtyping (å®éã«ã¤ã³ã¿ã¼ãã§ã¤ã¹ã®åã®å®ç¾©ãçç¥ã§ãã structural typing ã®è¨èªãããã¾ããå¾è¿°) ã®ãããªåããµãããã¨é ã®ä¸ã«ããã¨æãã¾ãããå®éã®ãduck typing ã¯ãã£ã¨ã¬ãã¬ãã§ãã
ãã®ä¾ã ãã§ãä¸çªã®ãã¡ãªããã§ããèå¼±æ§ï¼åãå®è¡æã¨ã©ã¼ããä½ãå®ã£ã¦ãããªãï¼å®è¡æã¨ã©ã¼ã«ãããªããåºåãå£ããå±éºãããï¼ã¯ååä¼ãã£ãã¨æãã¾ãã
ã§ããããã®ãã¡ãªããã¯éå®ç¨çã¨ããã»ã©ã¯å¤§ããããã¾ãããã¾ãããããªããºã«çãªã³ã¼ããæ¸ããªãéããã¡ããã¨å®è¡æã¨ã©ã¼ã§ä¸å¯§ãªã¨ã©ã¼ã¡ãã»ã¼ã¸ã¨ããã¯ãã¬ã¼ã¹ãåãã¦æ¢ã¾ãã¾ãããªã®ã§ãæ°è»½ã«ãªãã©ãå®è¡ã§ãããããªã¹ã¯ãªããã§ããã°ãå®è¡æã¨ã©ã¼ãè¦ãªããä¿®æ£ãããµã¤ã¯ã«ã¯ããã«ããé ãè¨èªã§ã³ã³ãã¤ã«ã¨ã©ã¼ãè¦ãªããä¿®æ£ãããµã¤ã¯ã«ããæ©ããã¨ã ã£ã¦ãããã¾ãã
ä¸æ¹ã®ã¡ãªããã¯ãã¤ã³ã¿ã¼ãã§ã¤ã¹ã®å®ç¾©ãè¦ããªãåã ãã³ã¼ããç°¡æ½ã«ãªããã¨ã§ãã Java ã§ã¤ã³ã¿ã¼ãã§ã¤ã¹ãè¦ãæéã§ã Python ã Ruby ãªãå®è£ ãèªãã¦ãã¾ããã¨ã ã£ã¦ããã¾ãã
ã¨ã¯ãããããã°ã©ã ã大è¦æ¨¡åãã¦ããã¨ããªãã¡ã¯ã¿ãªã³ã°ãã¼ã«ãé解æãã¼ã«çã«ååãªãã³ããä¸ããããªãããã«æ¹ä¿®ã³ã¹ããã©ãã©ãè¨ãä¸ããå±éºæ§ãããã¾ãã Python ã type hinting ãå°å ¥ããã®ããããçç±ã§ãã Python èªä½ãåã使ãã®ã§ã¯ãªãï¼å°æ¥ããããã¢ã¼ãã追å ãããå¯è½æ§ã¯ããã¾ããï¼ã mypy, Jedi, PyCharm ãªã©ã®é解æãã³ã¼ãè£å®ãIDEãåæ å ±ã使ãã®ã§ã typing ã§ã¯ãªã type hinting ã¨å¼ãã§ãã¾ãã
Python ã® Gradual Typing
Python ã® type hinting ã§ä½¿ããã¦ããã·ã¹ãã ã PEP 483 ã§ç´¹ä»ããã¦ãã Gradual Typing ã§ãã 漸é²çåä»ãã¨ã¯ä½ã ãè¯ãç´¹ä»è¨äºãªã®ã§åèã«ãã¦ãã ããã
ãã£ããã¨è¨ãã°ã Gradual Typing ã¨ã¯ã é常㮠Subtyping ã« Any ã¨ããç¹æ®ãªåã追å ãããã®ã§ãã
é常ã®é¨ååé¢ä¿ã¯é åºé¢ä¿ã«ãªã£ã¦ãã¦ãæ¨ç§»å¾ãæãç«ã¡ã¾ããã¤ã¾ãã B ã A ã®ãµãã¯ã©ã¹ã C ã B ã®ãµãã¯ã©ã¹ãªãã C 㯠A ã®ãµãã¯ã©ã¹ã§ãããã¾ãã (C > B > A) ãªã®ã§ã C åã®å¤ã A åã«ã¢ãããã£ã¹ãï¼ãµãã¿ã¤ãããã¹ã¼ãã¼ã¿ã¤ãã¸ã®ãã£ã¹ãï¼ãå¯è½ã§ãã
ä¸æ¹ã§ Any åã¯é¨ååé¢ä¿ã®å¤ã«ãã¦ããã¹ã¦ã®åãã Any ã«ãã£ã¹ãã§ãã¾ããã Any ãããã¹ã¦ã®åã«ãã£ã¹ãã§ãã¾ããã§ããé¨ååé¢ä¿ã®å¤ã«ããã®ã§æ¨ç§»å¾ãå½ã¦ã¯ã¾ããã A ã Any ã«ãã£ã¹ãã§ãã¦ã Any ã C ã«ãã£ã¹ãã§ããããã¨ãã£ã¦ãç´æ¥ A ãã C ã¸ã®ãã£ã¹ãã許ããã訳ã§ã¯ããã¾ããã
ãã® Any 㯠type hint ãã¾ã ã¤ãã¦ãªãã¨ããä»»æã®åãåãããã¨ããæå³ã«ãªãã¾ããä¾ãã° JSON ã® object ã dict ã«ããã¨ããããã°ããªãåãã³ã㯠Dict[string, Any]
ã«ãªãã¾ããï¼é å¼µã㨠Any ã§ã¯ãªã Union ã¨ãããå¹¾ã¤ãã®åã®ã©ãããåã«ãªãã®ã§ããããã® Union ãåãå¾ãåã®1ã¤ã JSON object ã表ã dict åã«ãªãã®ã§ãå帰çãªå®ç¾©ããããã¨ã«ãªãã¾ããï¼
ãã¦ãtype hinting ãã©ãã©ãæ¸ãã¦ããã¨ãçµå±éçåä»ãè¨èªã¨åããããã³ã¼ããå¢ããããªæ°ããã¾ãã
ãããå®éã«ã¯ããã¾ã§å¢ããªããã¨ãå¤ããã§ããã¨ããã®ã¯ãä¸ã®ä¾ã§ãã£ããããªãã¢ãã¯ã«ããæ¿ããããã ãã«ã¤ã³ã¿ã¼ãã§ã¤ã¹åãç¨æãããå¿ è¦ããªãããã§ãã ã¢ãã¯ãªãã¸ã§ã¯ãã Any åã«ãã¦ãã¾ãã°ãtype hint ã«å ·è±¡åãç´æ¥æ¸ãã¦ãå¼æ°ã«ã§ãã¢ãã¯ãçªã£è¾¼ãã¾ããããããã mypy ãªã©ã®é解æãã¼ã«ã®å¯¾è±¡ãããã¹ããã£ã¬ã¯ããªãå¤ãã¦ãã¾ãã¨ããæã ã£ã¦ããã¾ãã
Python ã® type hinting ã¯ã¾ã ã¾ã éçºéä¸ã§å®ç¨æ®µéã¨ã¯è¨ãé£ãã§ãããã ããããããªæãã§ãåçåã®ç¹å¾´ã殺ããã¨ç¡ãéçåã®ã¡ãªããã®ä¸ã¤ã§ããæåããã¼ã«ã®æ¯æ´ãåãè¾¼ãæ¹åã§é²ãã§ãã¾ãã
Ruby Kaigi ã§èªãããæ§æ³ã§ã¯ã Python ããããã£ã¨ããã°ã©ãã¼ãæ¸ãåæ å ±ãæ¸ãæ¹åã§èãããã¦ãããããªã®ã§ãã©ããªã£ã¦ããã®ãæå¾ ãã¦è¦å®ãããã¨æãã¾ãã
追è¨: éç㪠duck typing
ä¸ã®ä¾ã§ã¯ structural subtyping 㨠duck typing ã®æ¯è¼ã¨ã㦠Go 㨠Python ãæ¯ã¹ã¦ãã¾ããããå®éã«ã¯ structural subtyping ã¯åã«é¨ååã«é¢ããã«ã¼ã«ã§ãããªãã®ã§ãç´æ¥æ¯è¼ã§ãããããªãã®ã§ã¯ããã¾ããã
å®éã«ãå¼æ°ã®åãã³ã¼ãä¸ã«æ¸ããªãã¦ãéç㪠duck typing ã¨ãã¹ããããªåå°åºãè¡ã£ã¦ãããè¨èª (OCaml ãæå) ãããã¾ããã¤ã¾ãã
def read_packet(s): n = s.recv(1)[0] return s.recv(n)
ãã®ã³ã¼ãããã "s ã®åã¯ã .recv(int) ã¨ããã¡ã½ãããæã£ã¦ãã¦ããã®ã¡ã½ããã®æ»ãå°ã¯æ·»åã¢ã¯ã»ã¹ (x[0]
) ã§ãããããªåã§ã..." ã¨ããæé»ã®åãå®è¡ããã«é解æã§å°åºãã¾ãããã¨ã¯ãã®é¢æ°ãå¼ã³åºãã¨ãã®å®å¼æ°ã®åããå°åºãããæé»ã®åã®ãµãã¿ã¤ããã©ããã structural subtyping ã§ãã¹ããã¾ãã
ãã®ã³ã¼ãããæé»ã®åãå°åºããã¹ãããã¯éç㪠duck typing ã®ç¨ã«ã¿ãã¾ãããåç㪠duck typing ã§ããã°ã©ã ãã¦ããããã°ã©ãã¼ã®é ã®ä¸ã«ãµãããã¨åå¨ããåã¨ãããªãä¸è´ããã¨æãã¾ãããã¶ã Matz ã® soft-typing æ§æ³ã«ãè¿ãã¦ããããåé ã® Matz ã®çºè¨ã«ã¤ãªãã£ãã®ã ã¨æãã¾ãã
åç㪠duck typing ã¯ãã£ã¨ã¬ãã¬ãï¼å¼æ°ã®åã§ã¯ãªãå¤ã«ãã£ã¦æ»ãå¤ã®åãå¤ãããªãã¦ãã¨ãã¶ã©ï¼ãªã®ã§ããã®éç㪠duck typing ã¯åç duck typing ã«å¯¾ããå®å ¨ãªéçåãã§ãã¯ã«ã¯ãªããªãã§ããã Python ã® Gradual Typing ã Any ãå°å ¥ããã®ã¨åãããã«ãªãããã®ã¯ãã·ã§ã³ãæããã¨ã§ãã¾ãé©ç¨ã§ããå¯è½æ§ãããã¾ãã