When I say "multiple inheritance", I think of a class having multiple parents (rather than implementing interfaces); and that requires more overhead just to support. But that's what the interfaces are for (Java and C#'s solutions, and OPIA works the same). Interfaces can "extend" each other, but they don't "implement" each other because they themselves represent contracts that classes are to keep; but an implementing class can certainly implement both of something.
Static allocation has it's nastiness (especially recursion); but it also greatly simplifies how and where things are stored in the general case. OPIA has some big features, but I can be used without all the OOP and just writing something to do a simple task ... I didn't want to make needless use of the stack in every case. Instead, recursion-detection and liveness-analysis will have values saved in the stack when not doing so would cause collisions with recursion. The liveness analysis and value-tracing keep this from happening to more than just the vars that need it, and some vars can just stay there if they need to be put back ... I've gone over this many times, and there are strong cases for both. But I recognize that it requires extra checks and work that would otherwise come for free; and I claim it's a fair trade at the least.
The idea of there being allocation functions written is entirely the idea
... but those would be coded and not built-in, and right now I am focused on what to build-in (though having that in mind is definitely an influence of other things). That is another reason references can be assigned to static things: perhaps someone uses allocation functions separately from the "new" mechanism, and just wants to assign to the resulting value (which happens to have been gotten dynamically within the function).
I didn't want variables to necessarily have to construct as they are declared; however, I could easily have the compiler complain when variables are used without having been assigned/initialized first (and that would certainly require the construction to happen first).
Assigning to a static allocation ... I was waiting for someone to say it was nasty
... it kinda is. However, this kind of thing happens all the time in assembly. For example, with {char[] str = "blah";}, the "blah" would be statically stored in the program as a preconstructed instance of a string. Compare that to {= new char[]("blah")} or {= char[]("blah")}. The syntax IS a bit nasty, but that's also to provide that if you do it, it's on purpose. ASM programs hard-code "records" of information all the time, in which each entry COULD be represented as a struct (has a uniform format). That's what that's about.
C# provides both "ref" and "out" parameters, such that "ref" arguments are required to be assigned/init'd before passing them in, and "out" params are required to have a value before the function returns. I was going to have the same thing, but use "in" and "out"; but I figured it would be simpler to just let "ref" be for either and just not impose any rule for assignment (and leave "in" and "out" as valid identifiers, since they are nice names); but I can switch back.
As for "new" and "val" ... GONE. I was considering them in the first place because the compiler MIGHT have been able to spare an instruction or two if it could make the copy during the pass; but I found it better to do it in the function body, and at that point it was just a shorthand. ... Yeah, where deep copies are needed, those don't make it any simpler, and can paint a false picture.
Closures are there basically because function-pointers exist. For something like "void affectStuff([byte=>] how) { ... }", it would be nice if a calling function wants to define the "how" in terms of local variables, e.g. sorting a localized list. But it's not meant to escape. The static allocation of vars meant that allowing them was trivial, and per the example I just gave, can be useful. As for the "undefined behavior", such a closure would actually work just fine -- the "undefined" part of it is that perhaps it suddenly coexists with another call to the function it came from, and suddenly there are value collisions ... that's a bit impossible to track, unless I provide a mechanism to lift the "free variables" out of the parent context; which I think adds more complexity than is needed. The two options I consider are (1) disallow closures to be returned from a parent context if it makes reference to local vars (passing is okay, and useful), or (2) allow them to escape and call it "bad practice" ... hmm... 1 is sounding better, but perhaps if the programmer is careful, they can get away with it? That might cause more problems if they are wrong though... it's probably better to have the restriction so keep things "safe".
I agree, casts should be in parens (all others are). On a side note, I came across an interesting conundrum: is it terrible to allow function-pointers of different types to have the same name? That's would be outright madness for other types; but it would be for the same reason that functions can have the same names so long as they take different arguments. ... In THAT respect, the function-pointer "cast" is really meant to be more of an "Oh, I mean THIS function" statement to resolve ambiguity, so I might leave off the parens and distinguish it from a cast ... sorry, it's not really a cast.
Structs are indeed meant to just be straight-up data containers; however, allowing member functions really doesn't hurt it, and can be convenient. The only difference is that the member function takes a pointer for the "this" (which is more efficient than copying a whole struct to a function which ought to act on it directly, rather than a copy; otherwise it wouldn't be declared as a member function). However, this is why inheritance and virtual functions are NOT allowed within structs, because they contain NO reference to any kind of descriptor or anything but their actual contents. I said they might contain a reference descriptors to interfaces they implement, but that's wrong; a struct instance is of a very specific type (because of the lack of inheritance), so if one needs to be boxed into an interface instance, there is not question about what descriptor to use (which will never be part of a struct instance, but stored statically somewhere).
Iterators -- I really thought about that, too. It's a technical difference, because those don't have to "iterate over something" per se; they can generate or compute something in series, and "enumerate" fit what they did better ... But I agree, it's a bit too close to "enumeration". I was going to call them "processes" (because whatever it's doing, it's a "process" that takes steps ... but I didn't want to confuse that with the idea of a parallel thread of execution). ... on thing further: It MIGHT be nice to have a for-each loop that takes one of those (or something that HAS one of those) and goes through until it's done; but that requires some more thought and discussion and particulars about how it would interface, etc. ... There'd be no way for it to apply to arrays, unless the compiler could infer the size; and idk about always assuming that char[]s are strings with a null char at the end... but anyway, how is "process"?
I wanted enums to be strongly purposed for use with switches, but not limited to that. The reasoning for forcing the values like is because (1) it makes it incredibly efficient with switches (a big motivation for even having them in my language), and (2) I wanted to present enums are a pure "choice" mechanism such that the value is only thought of as one choice or the other; rather than ever being the result of a computation. I wanted to keep them abstract, and mainly as a "choice" mechanism. The user would never see the underlying values. I feel that forcing this would generate more efficient code in most cases; and otherwise you can always use a non-enum type. ... I did find a way to allow up to 255 values, though (switched perform best when there are only 43, require another instruction up to 86, and then a few more to handle more than that).
DOCUMENTATION UPDATED:
http://tinyurl.com/z80opia