"What does this level of openness buy programmers? Mostly yet another assembly layer to hack kludgily at, it seems to me."
I don't know. But at the same time, I tend to follow pg's mentality that if I can't find a logical reason to disallow it, then I should allow it.
So a better question would be, should we not allow this functionality, and if so, why? You can argue that my particular solution is kludgy, hacky, or any other pejorative term, but that doesn't answer the question, "is this a good idea or not?"
Obviously I wouldn't expect this function mutating to be common place. In case it wasn't obvious, I'm mucking around with low-level special-case stuff here. Stuff that just isn't possible in pgArc. A kludgy solution that works is better than no solution, in the situations where you need it.
One of my goals with py-arc is to get as much as (reasonably) possible written in Arc itself. Once you go down far enough, you eventually get to low-level "assembly kludge". Do you have a better idea for a way to get function inspecting/mutating (or something equivalent) in a way that's better than my proposal?
py-arc isn't even at 1.0, and implementations can change. I'm much more interested in knowing whether the idea itself is good or not. Though, if you do have a suggestion for a better implementation, I'd like to hear that too!
---
"I'm not sure slots for arg lists and body are the right separation. I can't imagine changing the arglist without the body, for example. Except maybe to add or remove defaults for args. In any other situation I'd want to change both at once. Might as well just run def all over again."
We're talking about the situation where you're dealing with somebody else's code. Obviously if it's your module, you can just change it yourself, but imagine somebody else writes a library, and you want to add a feature, or fix a bug.
If the library isn't designed well, the only way to do this might be to mutate a function, so calling `def` isn't an option. Or perhaps the library is designed well, but the particular situation the library is trying to solve requires mutating functions.
Ordinary Arc code wouldn't use function mutating, but perhaps somebody has a special use-case for it. Imagine a debugger, or a profiler, or a logger. Something that needs to inject itself into other people's code in a way that works perfectly every time. Mutable functions might be useful in that situation.
A code walker could also make use of the `environment` attribute to gather information about the function's closure. rocketnia mentioned a potential use-case for this[1].
I don't know exactly where this might be useful, but I think there's at least one situation out there where it would be useful. And since this would be really easy to do given py-arc's architecture[2], it just makes sense to expose it to Arc, unless there's a good reason not to[3].
* [2]: py-arc internally uses this idea. Every Arc function has an opts, rest, and body attribute. Calling a function evals the body attribute, and returns the last value (it's a teensy bit more complicated than that, but that's the basic idea). So it's simply a matter of exposing the internal details to Arc, and message passing can do that easily.
Rereading my original comment, my question "What does this level of openness buy programmers?" was too baldly stated. As I was writing it I was thinking something more like "can you give me an example where this would be useful?" (going back to aw's advice at http://arclanguage.org/item?id=14264) And you and others have since given examples.
When I said 'hack kludgily at', I was thinking, "can we find a better way?" So combining the two I'd rephrase my original statement as:
"Can you give some examples of where this is a problem? Assuming it's a problem, I'm sure we can come up with more elegant solutions."
That's closer to what I was thinking, and I don't think I'm revising history either. My apologies for the tone.
"Can you give some examples of where this is a problem? Assuming it's a problem, I'm thinking about more elegant solutions to the problem."
The reason I didn't give examples is because I didn't have any. It was just a, "oh hey we can make Arc more hackable if we do this" sorta thing. I figured we'd find use-cases for it later, and, well, we did.
As for a more elegant solution... this solution is using message passing. So to get the environment of the function `foo`, you would use this:
foo<-environment
And to get the closure for foo, you'd use this:
foo<-environment<-outer
How would you make that more elegant? Does it need to be more elegant, considering that accessing a function's closure is a pretty rare and special-case thing to do? Would you prefer to use `(get-closure foo)` instead? Oh, wait, you can do that:
(def get-closure (x)
x<-environment<-outer)
It's easy to write function wrappers that make message passing more palpable, but it's a lot harder to use functions to simulate message passing. So it makes sense for the low level things to be done with message passing, and then write wrappers for them.
---
"My apologies for the tone."
Mine wasn't exactly happy rainbows either, you know. I don't mind people saying that an idea of mine is kludgy, but I'd at least like some justification for it. You know, an example where my idea is noticeably kludgy, or perhaps a different solution that is demonstrably less kludgy.
Yeah like I said at http://arclanguage.org/item?id=14418 I even withdraw my sense that there must be a better way. Next time, think before hitting submit :)
It's perfectly understandable that you want a nice, sleek, shiny high-level thing that walks your dog and washes your dishes, but at some point you need the low-level stuff.
And because I'm sorta kinda writing an interpreter, not only am I thinking about low-level stuff, but I'm actually implementing it, so my posts and "great ideas" will probably be about low-level stuff for a while.
So, don't worry about it. You're up there in Arc-land thinking about high-level stuff, whereas I'm down here in low-level Python, thinking about low-level stuff. We both need to try to remember that better.
I'd still be interested in hearing if you come up with a better idea.
Oh! I know! We can write an Arc program that reads our minds, it would be the most elegant and concise language ever! :P
Yeah the toolchain-enhancement use cases make sense.
"If the library isn't designed well, the only way to do this might be to mutate a function, so calling `def` isn't an option. Or perhaps the library is designed well, but the particular situation the library is trying to solve requires mutating functions."
I don't follow this.
Adding features to a function is the whole point of extend. Can you think of an example where it wouldn't suffice?
"if I can't find a logical reason to disallow it, then I should allow it."
That isn't a defense to the question, "is this the right representation?" Even PG isn't allowing non-sexp syntax, as an extreme example. I think "is there a better way to do this" is a fine logical reason.
To summarize: I now agree there's value in making a language's constructs introspectable. I'm less convinced that this specific approach is the best one. But you've gotten me thinking about alternatives :)
Aaand now your extension can access the hidden data. But that's only possible if closures are transparent. And it might be easier to just mutate the function directly:
(= foo<-body ...)
Incidentally, <- would be ssyntax that lets you easily access an attribute. Thus, the following two would be equivalent:
foo<-bar
(get-attribute foo 'bar)
---
"I think "is there a better way to do this" is a fine logical reason."
Sure, but I don't know of any better ways, nor has anybody presented them, so for now I'm focusing on whether the idea has merit. We can fix the implementation later.
P.S. If you consider this idea to be kludgy, then you probably consider message passing in general to be kludgy. :P How would you like to be able to access the data, then?
---
"But you've gotten me thinking about alternatives :)"
"Extend can't access the hidden data in the closure, but by making functions transparent, you could."
That's a great example, thanks.
"Sure, but I don't know of any better ways, nor has anybody presented them, so for now I'm focusing on whether the idea has merit."
Yeah that makes sense.
In fact, this is a fine implementation. Once I think of it as exposing the compiler's data structures to the language, separating arg lists and body makes a lot of sense.
"In fact, this is a fine implementation. Once I think of it as exposing the compiler's data structures to the language, separating arg lists and body makes a lot of sense."
Well, yeah, how else would you do it? This is low-level stuff. :P