= Perl6-ObjectSpace Design Notes # 1st draft, 2005-10-30, by Stevan & Autrijus. "A minimal runtime to implement the metamodel" The metamodel is more portable iff it's built with a runtime that is: - well defined runcore primitives - fixed set of intrinsics and coercion rules == Glue::Overload (P5) - "Glue" namespace for all the interop magics - whatever works for p5-harnessed tests also works for p5 interop - interop means dealing with p6 box and unboxed vals in p5 land - overload is one of the ways to make it saner - eg. str and num needed to be comparable (with eq/==) - not going to be neccessary for the metamodel to boot - but works with perl5 host environment more "naturally" == OO primitives (was Chaos.pm) What we are after at this moment is really the API - (aka tests on the MM::* stuff) - i.e. the chaotic thing a runtime need to support mm - attribute - method - dispatching to closures - "magic sugar" Dispatchable thing in old P6::MM - opaque - dictionary, aka "hash" stuff, with fixed Str keys Base on YARV: http://www.atdot.net/yarv/insnstbl.html - Chaos API for ruby - Ignore everything from 52nd onwards (op seqs optimized) - The class building parts are minimal - By testing those bytecode APIs - you basically guarantees that anything implements those can run Ruby - bootstrapping trivial (fixed seq of calling bytecode to establish C.isaO) - also very easy to verify for consistency - also if we use something close to this API we get ->YARV for free, whee - refactor the YARV stuff by type into Core::attr, Core::meth, etc - call this bootstrap code in the same sequence on any runtime - that implements this can share this microcode - shared among the backends via machine translation - minilang is just function calls (but nested!) - start with p5 func calls and we can always machine trans it to js/hs/pir - we still need sugar to test interop - make testing p5-p6 cross object uses easier - we don't want either .as_str or exccesive TIETIETIE == Container Types Objects that has type restriction fields (validations) - FETCH/STORE/etc methods associated with them - not really different from any object - containers are affected by methods of objects: class Object is extended { method greet { say 'Hi' } } @ARGS.greet; # should work Speculative "Val" class that does not cover containers? class Val is extended { method greet { say 'Ho' } } $something.greet; # this passes to the Val in it @ARGS.greet; # won't work then Scalar containers dispatches meth calls back to vals $this.tied; # calls Container meth $this.blah; # calls Val meth Intrinsic classes (overridable in MM land) for %ENV Make all Hash ordered... - ...should be possible to just do it in userland - (we agree tentatively on tentative things.) - fglock++ already tied them back to MM anyway. == Value Types May be _very_ differently implemented for each runtime: - Intrinsics are enumerable (fixed set of behaviour) - Each runtime may implement unspecced intrinsics (Symbol? Map?) - The specced ones all need to behave exactly the same - Runtimes have to approach the API using - a thin layer of bridge to their own intrinsics (if any) or emu - whatever performance hack in their disposal (!going to look inside) Val = - Previously in the hs runtime List is just [Item] - turns out to be bad idea - can't splice naturally - doesn't deque bothways - reverse() is pain - et cetera - fglock's model: List as part of EnumIntrins - so "Item" is just "Val" - "Seq" is natrually subsumed - enreferencing when you do `$x = (1,2,3)` is not value/core's job - Good Idea (seeing how larry may change autoref rules any time) == Contexts One extra slurp(typ)|item(typ)|void info into every func call - At compile time, subject to static analysis (for the "luke" half of p6) - /me praises p6 being a gradient of stevaness to luquiness - We Can Ignore The Static Analysis until 6.2831.0 - But leave enough compiler info around so analysis can be introduced (unlike in PyPy where everything is stripped by compiler and they had to dry-run the program to obtain types, which is heuristics -- which means "we don't know what it's doing really") For p5 runcore, piggyback it on Want - s(any), i(any) & v are going to be the usual case - per 80% rule, we just use wantarray for them - for the 20% where we are MMD'ing or given(want)'ing: - use a special context somehow (abuse Want/COP) - pass the type as an extra info to be fetched by &*want - p6-side want() and MMD stuff will parse it themselves - again *not* runcore/obj/meth's business - (although maybe part of the chaos args to "callmeth/func") A primitive in Chaos to fetch the current "want" - in parrot it's a single enum (s/i/v) and a single tynum (Str) - bulit into interpreter context itself - you can get/set it anytime (for amusing effects) - want() that returns a intrins Cxt (may box) The codegen at PIL tree level _knowns_ Cxt=Any and !=Any - for =Any part we gen p5 that just uses p5cxt for bug-for-bug combat - for !Any part we gen p5 with extra shuffling of Want.pm - bribe the COP - our &*want will read the COP tag info that is a Ptr - dePtr back to the obj in MM that rep the complex/simple type - (note Typ is a intrinsic for monotypes) - it's just `where {...}` and TypeSets that needs MM level fun - all responsibility in the p5 codegen (to differ between the styles) == Context example 4 + f(); 's' ~ f(); multi Str f {...} multi Int f {...} # before static analysis, we can always desugar into: sub f { given(want) { when Str { ... } when Int { ... } } }