= 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 = <Int Num Complex Str Ref Bit Pair Junc Type Code Cxt>
- 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 { ... }
}
}