= 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 { ... }
    }
}
