# dynamic

Definition: | class identifier dynamic [extends base] { [(public|private)[:]] ( field | method ) [ ',' ... ] } end class -- or -- class|identifier variable ( ';' | '=' ( new() | expr ) ) [ ',' ... ] -- or -- bool res = class|identifier(object o)
Description: | By default, you have to explicitly declare all fields and methods of each class/structure, however you can also create fully dynamic classes by making the base class dynamic.
pwa/p2js: | Not supported.
Example: |
    class wobbly dynamic
    end class
    wobbly wobble = new()
    ?wobble.jelly           -- NULL
    wobble.jelly = "green"
    ?wobble.jelly           -- "green"
Obviously you can create several fields/methods as normal, or as shown above create all of them dynamically. All dynamically-added fields are implicitly public and of type object.
Implementation: | As per struct
See Also: | class
Technicalia | In some cases it may help to explicitly store a dynamic element in a (local) variable of the appropriate type, especially when it is a dymanically embedded class/struct. Dynamic routines would typically be implemented as integers, to which is assigned a standard routine_id(), and would usually need to be invoked via an explicit call_func() or call_proc(), such as `call_proc(p.show,{p})`, or rather as an OO-pagan, I simply don’t get how/why you w/could have `p.show()` at the same time as wanting/needing to declare `show` dynamically. One thing you can trivially do is declare a class method `procedure task();` (ie virtual) along with actual methods easy() and hard(), and then just `p.task = p.easy` or `p.task = p.hard` before invoking `p.task()`. It is questionable as to whether there is any actual benefit in hierarchies of, and hence extending, dynamic classes, but you can. The compiler currently rejects abstract + dynamic, but I’m open to persuasion if you’ve got a proper use for it. The dynamic keyword is optional when extending an already dynamic base class. You cannot disable dynamic half-way down the tree. Technically speaking, class/struct field access is a subversion of subscripting, such that `s.field` is the same as `s["field"]`, except that in the former you are pretty much obliged to reference pre-existing fields whereas the latter syntax allows a fully dynamic field name to be constructed at run-time. Note the following:
    constant one = "two"
    class thing
        string one = "one",
               two = "two"
        function tre()
            return "tre"
        end function
    end class
    thing s = new()
    ?s.one          -- "one"
    ?s.two          -- "two"
    ?s.tre          -- 2473 (a routine_id)
    ?s.tre()        -- "tre"
    ?s["one"]       -- "one"
    ?s["two"]       -- "two"
    ?s["tre"]       -- 2473 (a routine_id)
    --?s["tre"]()   -- invalid syntax
    ?s[one]         -- "two" (because of that constant!)
    --?s[two]       -- two undefined (even though s.two exists)
    --?s[tre]       -- tre undefined (even though s.tre exists)
    --?s."one"      -- invalid syntax
    --?s[3]         -- compile-time and/or run-time error
One other small point to note: while `s.employee` is equivalent to s["employee"], `s.employee.name` is (possibly) legal whereas the square bracket syntax is strictly single-level only and s["employee"]["name"] is treated as invalid syntax, and therefore if you are using an expression for "employee" rather than a literal string, the latter statement must be broken up into two or more lines, with appropriate (or base) struct/class types on any temporary variables, in order to give the compiler sufficient hints. In other words all dynamically-created fields are implicitly "object", and hence must be stored in an explicit struct/class variable before any further dot or ["string"] field-accessing operations can be performed. Likewise `s[expr].field` is never valid, but `s[expr][int]` might sometimes be, ie when the second and subsequent [] are of the more traditional integer-index subscript variety. Another way of saying this is that in C++ you can pass around (a reference to) an instance as a `void*`, but it must be cast to some appropriate class before using dot notation. In a similar fashion, you can pass Phix struct/class references about as objects (or store them in tables/sequences), but /must/ store them in local struct/class type variables or routine parameters, before you can use dot notation. By default the compiler assumes all "dot /and/ []" are traditional integer subscripting of sequences, unless a variable/parameter is unambiguously a struct/class (that is, according to its declaration). Dynamic class instances are simply implemented as independent dictionaries, with dot-notation and automatic cleanup. Obviously you should expect fairly disappointing figures from a pointless benchmark: p["index"] is without any doubt going to be at the very least 5 times slower than p[1], probably much worse, and even the most mediocre of programmers could apply optimisations way better than any compiler ever could. Only use dynamic classes when you value the improved code clarity more than the 0.0001s being lost, and yes, ten thousand dynamic class instances is probably fairly likely to take (aka waste) a whole second to set up, use, and tear down, if not more, but then again if you only have a dozen or so of them, lightly used, then you simply just don’t care one jot about their performance.