Hm... I gave it some thought, and ar's dynamic variables might actually be okay. It'll make certain things a little bit clunkier, though.
For starters, there would be an implicit "self" variable. Rather than using "letr", "object" would use "w/self". The problem with doing that, is then you would need to call w/self yourself:
(= foo (object ...))
(w/self foo ...)
Why? Well, let's say foo grabs an attribute from bar:
(= bar (object x (fn ...)))
(= foo (object x bar<-x))
If you try to call foo<-x, the self parameterization will be all screwy, so you'll need to use w/self to fix that. One way to fix this would be to have a "bind" function or similar:
(= foo (object x bind:bar<-x))
Clunky, but probably still better than giving every method a "self" attribute... I could even try making it so the object constructor automatically binds... that might work. In any case, it would be kinda hacky and clunky, but if it worked, we could get very concise code, while still gaining the benefits of pseudo-dynamic scope[1].
---
* [1]: I'm calling it pseudo-dynamic because I think it's mixing dynamic/lexical together. "self" should by default always be scoped to the object that is currently being used, but it should be possible to override that with "w/self".
Things get more complicated when an object's method calls a different object's method, or when you introduce things like inheritance... I can tell you how I would expect it to behave, the complicated part is actually making it behave that way.
Putting in a "self" parameter for all methods would basically solve this, but at the cost of verbosity, and a couple other things. For instance, you wouldn't be able to use existing functions like "is" or whatever as methods, because their argument list would be different.
So you'd have two types of functions: those designed for objects, and those that aren't. I think it'd be better to not have that kind of separation.
"Things get more complicated when an object's method calls a different object's method, or when you introduce things like inheritance... I can tell you how I would expect it to behave, the complicated part is actually making it behave that way."
This is where something like Lathe's secretargs might come in handy. If we made a secretarg for "the object the function is invoked on", then it's like every function in the language has it as a lexical parameter. Traditional function calls just pass a default value, and traditional functions just ignore it; you have to use special-purpose forms to define secretarg-aware functions and pass those arguments in. Is this close to what you have in mind?
A failure secretarg is how I hacked in failcall to Arc--and now JavaScript--and I'd also make a secretarg if I ever felt the need to implement keyword arguments. (Secretargs are essentially first-class keyword args without names, but one of them can hold a more traditional keyword table or alist.) The catch is that things like Arc's 'memo and JavaScript's Function#bind() aren't written with secretargs in mind, so they're not especially seamless with the language. But I think it would be cool to add secretargs to ar on a more core level. ^_^
"If we made a secretarg for "the object the function is invoked on", then it's like every function in the language has it as a lexical parameter."
Hello dynamic variables!
---
"Is this close to what you have in mind?"
Sorta. The idea is close, but your way looks too verbose. I want it to be really short and simple, so having to define methods in a special way does not sound good to me. I want them to be plain-old functions.
I have an idea for what I'm going to do, and I think it'll work, because in ar, lexical variables always take precedence over dynamic variables, from what I can tell.
By the way, right now I only care about ar compatibility, since ar has nifty stuff like dynamic variables, which I've come to love. This not only should make the library shorter and easier to understand, but I honestly can't care much about compatibility, because my library kinda needs defcall, which isn't standardized[1] (and isn't even in Arc/3.1 at all)
Secretargs happen to be implemented in terms of dynamic boxes. The benefit of secretargs is that you can always pass the default value just by making a normal function call; you don't risk propagating the existing dynamic value into the call. Whether that's important in this case is up to you. ^_^
Oh, and I don't think we can say anything's standardized in Arc at all. :-p The standards are just implicit assumptions around these parts.
Note: when I said "standardized" I meant in the "de facto standard" way. Arc has plenty of those. :P
I agree that Arc has essentially no de jure standards[1], and I think that's a good thing.
---
* [1] The closest thing would probably be whatever pg does, but that would only concern the question of what official Arc is; other implementations would be free to either follow official Arc, or branch off into a different Arc-like dialect.