=begin pod :kind("Type") :subkind("class") :category("metamodel")

=TITLE class Metamodel::ClassHOW

=SUBTITLE Metaobject representing a Raku class.

    class Metamodel::ClassHOW
        does Metamodel::Naming
        does Metamodel::Documenting
        does Metamodel::Versioning
        does Metamodel::Stashing
        does Metamodel::AttributeContainer
        does Metamodel::MethodContainer
        does Metamodel::PrivateMethodContainer
        does Metamodel::MultiMethodContainer
        does Metamodel::RoleContainer
        does Metamodel::MultipleInheritance
        does Metamodel::DefaultParent
        does Metamodel::C3MRO
        does Metamodel::MROBasedMethodDispatch
        does Metamodel::MROBasedTypeChecking
        does Metamodel::Trusting
        does Metamodel::BUILDPLAN
        does Metamodel::Mixins
        does Metamodel::ArrayType
        does Metamodel::BoolificationProtocol
        does Metamodel::REPRComposeProtocol
        does Metamodel::InvocationProtocol
        does Metamodel::Finalization
            { }

I<Warning>: this class is part of the Rakudo implementation, and is not
a part of the language specification.

C<Metamodel::ClassHOW> is the metaclass behind the C<class> keyword.

    say so Int.HOW ~~ Metamodel::ClassHOW;    # OUTPUT: «True␤»
    say Int.^methods(:all).pick.name;         # OUTPUT: «random Int method name␤»

=head1 Methods

=head2 method add_fallback

    method add_fallback($obj, $condition, $calculator)

Installs a method fallback, that is, add a way to call methods that weren't
statically added.

Both C<$condition> and C<$calculator> must be callables that receive the
invocant and the method name once a method is called that can't be found in
the method cache.

If C<$condition> returns a true value,
C<$calculator> is called with the same arguments, and must return the code
object to be invoked as the method, and is added to the method cache.

If C<$condition> returns a false value, the
next fallback (if any) is tried, and if none matches, an exception
L<of type X::Method::NotFound|/type/X::Method::NotFound> is thrown.

User-facing code (that is, code not dabbling with metaclasses) should use
method C<FALLBACK> instead.

=head2 method can

    method can($obj, $method-name)

Given a method name, it returns a L<List|/type/List> of methods that are
available with this name.

    class A      { method x($a) {} };
    class B is A { method x()   {} };
    say B.^can('x').elems;              # OUTPUT: «2␤»
    for B.^can('x') {
        say .arity;                     # OUTPUT: «1, 2␤»
    }

In this example, class C<B> has two possible methods available with name C<x>
(though a normal method call would only invoke the one installed in C<B>
directly). The one in C<B> has arity 1 (i.e. it expects one argument, the
invocant (C<self>)), and the one in C<A> expects 2 arguments (C<self> and
C<$a>).

=head2 method lookup

    method lookup($obj, $method-name --> Method:D)

Returns the first matching L<Method|/type/Method> with the provided name. If no
method was found, returns a VM-specific sentinel value (typically a low-level
NULL value) that can be tested for with a test for
L<definedness|/routine/defined>. It is potentially faster than C<.^can> but does
not provide a full list of all candidates.

    say Str.^lookup('Int').raku; # OUTPUT: «method Int (Str:D $: *%_) { #`(Method|39910024) ... }␤»

    for <upper-case  uc> {
        Str.^lookup: $^meth andthen .("foo").say
            orelse "method `$meth` not found".say
    }
    # OUTPUT:
    # method `upper-case` not found
    # FOO

=head2 method compose

      method compose($obj)

A call to C<compose> brings the metaobject and thus the class it represents
into a fully functional state, so if you construct or modify a class, you must
call the compose method before working with the class.

It updates the method cache, checks that all methods that are required by
roles are implemented, does the actual role composition work, and sets up
the class to work well with language interoperability.

=head2 method new_type

    method (:$name, :$repr = 'P6opaque', :$ver, :$auth)

Creates a new type from the metamodel, which we can proceed to build

    my $type = Metamodel::ClassHOW.new_type(name => "NewType",
                                            ver => v0.0.1,
                                            auth => 'github:perl6' );
    $type.HOW.add_method($type,"hey", method { say "Hey" });
    $type.hey;     # OUTPUT: «Hey␤»
    $type.HOW.compose($type);
    my $instance = $type.new;
    $instance.hey; # OUTPUT: «Hey␤»

We add a single method by using
L<Higher Order Workings|/language/mop#index-entry-syntax_HOW-HOW> methods, and
then we can use
that method directly as class method; we can then C<compose> the type, following
which we can create already an instance, which will behave in the exact same
way.

=end pod
