i question, if someone is seriously voting for the 'relative to parent' approach, since it is full of troubles:
I think, I do. (if seriously is another question...) to me an abstraction is like an include function (like for example in php). let's say I create an abstraction that plays soundfiles and the filename can be given as an argument or messages, then I want to write [mysfplayer sounds/1.wav]. in this case, I want the file be relative to the "parent" patch, because the parent patch will be in my project folder, but the abstraction will be somewhere in an abstraction directory.
Right -- is an abstraction like an include (macro?)? Or is it more like a c file which is separately compiled and linked? Or is it like a class definition which can have multiple instances, and might have a distinction between "public" and "private?" I don't think any of these analogies is quite general enough to be satisfactory. Your example is more complicated if your [mysfplayer] also lives in a different subdirectory -- is there a consistent (and/or idiot-proof) way of finding sounds/1.wav?
I think I prefer the 'relative to topmost' approach as well, if only because I tend to want to think of abstractions as objects. The problem is, for most built-ins your path is declared at startup or in the parent patch, so things get a little itchier -- you need to be able to allow the path to be declared in the main patch, but you need to have an abstraction whose file might be located somewhere deep in that path inherit from the main patch the absolute paths of resources located in other directories, which is a little different problem than what happens to a declare inside an abstraction. Depending on how things are defined, you could have soundfiles living in the same directory as the main patch which an abstraction living in a subdirectory can't find using the same name.
For myself, I'd like to make some of the ideas I've seen in recent posts more explicit so I know I'm understanding the problems correctly.
So then let's say you have a complicated abstraction called [GUI_ambi_pan~].pd which you keep in ./GUI_ambi_pan/ (relative to the main patch), and you've defined it in such a way that stereo soundfiles which store, say, realtime azimuth and elevation coefficients, can be passed to it with $2. For it to act transparently like an object you need it to inherit access to everything the patch it's instantiated in has access to pathwise, and with the same name, and again this is a deeper problem than what a [declare] inside an abstraction does.
On the other hand, let's say it also has a junkload of helper abstractions located in ./GUI_ambi_pan/helpers (similar, maybe, to a set of static functions in a C file or the private functions in a class definition), you might want a way to insulate the main patch from the abstraction's helpers -- or the flip side is you don't want the main patch to need to know about the abstraction's helpers in order to have them instantiated. A "public/private" distinction for sets of abstractions would still have to be defined pathwise.
If these are the problems, it leads me to believe that perhaps the -path syntax is too ambiguous to effect sufficient generality to be of any required specific use for relative paths inside of abstractions -- it might help the problem to have different flags for different situations (at least the following):
absolute paths using names defined relative to the parent (like declaring generally that abstractions behave like objects, using names you would use for built-ins).
1.1) a switch for inside an abstraction declaring that it will search for files using names relative to its parent (this abstraction should behave like an object).
child to its parent, with the path defined relative to the parent (treats the abstraction more like a macro - you could use this e.g. to define a main patch's path using an abstraction, which might be useful for complex declarations in something like a sandbox environment -- the same as just using the [declare -path ...] in the main patch, but as a ready-made set of things to include).
2.1) a switch for inside an abstraction to export an absolute path setting from a child to its parent, with the path defined relative to the child (I'm trying to think of a good use for this -- maybe if you wanted [soundfiler] and [my_groove_box~] to be able to access "sounds/johnson.wav" which lives in a subdirectory "sounds" of the directory my_groove_box~.pd lives in, and access it by the same name -- I don't think this is particularly useful and might be logically inconsistent).
relative to an abstraction's file (and by default unknown to the parent unless also declared there) -- probably overrides 1) just for this path? In this case, if 2) or 2.1) is used for this path as well, you're using the abstraction as a kind of hybrid object/macro, where path is relative to the actual files -- there could be a global switch for this, too, or it could be the default.
3.1) a switch for inside an abstraction to declare that such a "local" path is also "private" (or "static," etc.)... probably overrides 1) just for this path? also throws an error when the same absolute path is declared by its parent. Also throws an error when this same path is declared using a 2) or 2.1) switch.
declaration is logically inconsistent, ambiguous, or when a resource or directory defined relatively is multiply defined somewhere in the search path -- and very well-defined default behaviors in the presence of an error (like with multiple [send~]'s with the same name).
to be defined recursively -- [declare -path -r ./100_folders/] grabs everything in that directory including its subdirectories and their subdirectories. This could be extremely useful in some situations, but breaky-breaky in a great deal of others. Harder to make proper and useful checks, and the error messages thrown concise and meaningful.
So what happens if 1.1) and 3) are set for two different directories, but it finds a file with the same name in both of them (and it's not the same file)?
I guess the bottom line for me is that I'm okay with fuzzy or dumb [declare] statements breaking patches as long as proper errors are thrown and errant states are handled consistently -- I feel like the problem is just syntactical enough to be solved logically, and we should not throw up our hands at the possibility that someone could define paths wrong or ambiguously, or that it might be complicated to do it correctly in a way that allows sufficient generality and consistency at once.
What I worry about is that solving anything like this might necessitate unwelcome changes to the current way paths are defined, which is why I would support adding flags to change the current (default) behavior, and enough flags to make this thing as expressive and powerful as needed.
Wow, I need to get to bed. Sorry for the long post.
Matt
On Thu, 2008-07-31 at 04:24 -0400, Matt Barber wrote:
i question, if someone is seriously voting for the 'relative to parent' approach, since it is full of troubles:
I think, I do. (if seriously is another question...) to me an abstraction is like an include function (like for example in php). let's say I create an abstraction that plays soundfiles and the filename can be given as an argument or messages, then I want to write [mysfplayer sounds/1.wav]. in this case, I want the file be relative to the "parent" patch, because the parent patch will be in my project folder, but the abstraction will be somewhere in an abstraction directory.
Right -- is an abstraction like an include (macro?)? Or is it more like a c file which is separately compiled and linked? Or is it like a class definition which can have multiple instances, and might have a distinction between "public" and "private?" I don't think any of these analogies is quite general enough to be satisfactory. Your example is more complicated if your [mysfplayer] also lives in a different subdirectory -- is there a consistent (and/or idiot-proof) way of finding sounds/1.wav?
I think I prefer the 'relative to topmost' approach as well, if only because I tend to want to think of abstractions as objects. The problem is, for most built-ins your path is declared at startup or in the parent patch, so things get a little itchier -- you need to be able to allow the path to be declared in the main patch, but you need to have an abstraction whose file might be located somewhere deep in that path inherit from the main patch the absolute paths of resources located in other directories, which is a little different problem than what happens to a declare inside an abstraction. Depending on how things are defined, you could have soundfiles living in the same directory as the main patch which an abstraction living in a subdirectory can't find using the same name.
For myself, I'd like to make some of the ideas I've seen in recent posts more explicit so I know I'm understanding the problems correctly.
So then let's say you have a complicated abstraction called [GUI_ambi_pan~].pd which you keep in ./GUI_ambi_pan/ (relative to the main patch), and you've defined it in such a way that stereo soundfiles which store, say, realtime azimuth and elevation coefficients, can be passed to it with $2. For it to act transparently like an object you need it to inherit access to everything the patch it's instantiated in has access to pathwise, and with the same name, and again this is a deeper problem than what a [declare] inside an abstraction does.
On the other hand, let's say it also has a junkload of helper abstractions located in ./GUI_ambi_pan/helpers (similar, maybe, to a set of static functions in a C file or the private functions in a class definition), you might want a way to insulate the main patch from the abstraction's helpers -- or the flip side is you don't want the main patch to need to know about the abstraction's helpers in order to have them instantiated. A "public/private" distinction for sets of abstractions would still have to be defined pathwise.
If these are the problems, it leads me to believe that perhaps the -path syntax is too ambiguous to effect sufficient generality to be of any required specific use for relative paths inside of abstractions -- it might help the problem to have different flags for different situations (at least the following):
- a switch for globally declaring that abstractions inherit the
absolute paths using names defined relative to the parent (like declaring generally that abstractions behave like objects, using names you would use for built-ins).
1.1) a switch for inside an abstraction declaring that it will search for files using names relative to its parent (this abstraction should behave like an object).
- a switch for inside an abstraction to export a path setting from a
child to its parent, with the path defined relative to the parent (treats the abstraction more like a macro - you could use this e.g. to define a main patch's path using an abstraction, which might be useful for complex declarations in something like a sandbox environment -- the same as just using the [declare -path ...] in the main patch, but as a ready-made set of things to include).
2.1) a switch for inside an abstraction to export an absolute path setting from a child to its parent, with the path defined relative to the child (I'm trying to think of a good use for this -- maybe if you wanted [soundfiler] and [my_groove_box~] to be able to access "sounds/johnson.wav" which lives in a subdirectory "sounds" of the directory my_groove_box~.pd lives in, and access it by the same name -- I don't think this is particularly useful and might be logically inconsistent).
- a switch for inside an abstraction to declare a "local" path
relative to an abstraction's file (and by default unknown to the parent unless also declared there) -- probably overrides 1) just for this path? In this case, if 2) or 2.1) is used for this path as well, you're using the abstraction as a kind of hybrid object/macro, where path is relative to the actual files -- there could be a global switch for this, too, or it could be the default.
3.1) a switch for inside an abstraction to declare that such a "local" path is also "private" (or "static," etc.)... probably overrides 1) just for this path? also throws an error when the same absolute path is declared by its parent. Also throws an error when this same path is declared using a 2) or 2.1) switch.
- a large set of error messages which are thrown when some path
declaration is logically inconsistent, ambiguous, or when a resource or directory defined relatively is multiply defined somewhere in the search path -- and very well-defined default behaviors in the presence of an error (like with multiple [send~]'s with the same name).
- a "madcap hijinks" solution, which would be to allow search paths
to be defined recursively -- [declare -path -r ./100_folders/] grabs everything in that directory including its subdirectories and their subdirectories. This could be extremely useful in some situations, but breaky-breaky in a great deal of others. Harder to make proper and useful checks, and the error messages thrown concise and meaningful.
So what happens if 1.1) and 3) are set for two different directories, but it finds a file with the same name in both of them (and it's not the same file)?
I guess the bottom line for me is that I'm okay with fuzzy or dumb [declare] statements breaking patches as long as proper errors are thrown and errant states are handled consistently -- I feel like the problem is just syntactical enough to be solved logically, and we should not throw up our hands at the possibility that someone could define paths wrong or ambiguously, or that it might be complicated to do it correctly in a way that allows sufficient generality and consistency at once.
What I worry about is that solving anything like this might necessitate unwelcome changes to the current way paths are defined, which is why I would support adding flags to change the current (default) behavior, and enough flags to make this thing as expressive and powerful as needed.
Wow, I need to get to bed. Sorry for the long post.
yo, i generally thinks as well, that it is a good idea to have a look at other programming languages to see how they handle such issues. but at the same time, we shall not forget, in what ways pd works differently. the concept of expanding pathes relative to _somehting different_ than file location is _new_ to pd and i still don't see why it should be necessary.
'relative to file location' is old school pd style, easy to understand and together with the concept of inheritance, it covers every use case i can think of (which implies that i would try to adapt the way i code to pd and not vice versa).
roman
___________________________________________________________ Der frühe Vogel fängt den Wurm. Hier gelangen Sie zum neuen Yahoo! Mail: http://mail.yahoo.de
'relative to file location' is old school pd style, easy to understand and together with the concept of inheritance, it covers every use case i can think of (which implies that i would try to adapt the way i code to pd and not vice versa).
I'd almost agree with you as long as inheritance were a strong part of the model.
But...
Say I'm teaching a computer music course, and I've created a big library of commented and documented abstractions to do all kinds of neat things. I've written a script to copy the files from some global location to the user's current directory, all of them put into a directory called ./cm101-abs/ This directory is further subdivided by abstraction function: cm101-abs/control/ cm101-abs/noise/ cm101-abs/math/ etc. In order to use them the students need to either alter their search path or put in a rather lengthy [declare] which might be beyond the scope of the first semester, or as part of the script I can give them a blank file with just the [declare] statement, which they can edit as they like.
But, if Pd had a simple flag which allowed an abstraction instance to export a [declare] path to its parent, using names relative to the parent, then I can make an abstraction with just the [declare] from above, but instead of -path I use some other flag. Then all the students have to do is include an instance of that abstraction in their patches and they have access to the larger suite of abstractions. I think of this roughly as something like including a header (providing access to the interface of objects defined elsewhere). This is much simpler for the students and the teacher, and as a bonus the students learn something similar to the "include" concept.
Now, let's say I have a fairly complex dynamically patched impulse-response convolution patch called [IRconv~] using [rfft~]'s all over the place, and it has a specialized abstraction called [fft-conv~] that's loaded dynamically into the patch which has arguments specifying the $0 of the parent abstraction, the block size, its associated delay (minus block delay), the name of a [table] in the abstraction to which is written a specified set of samples from the impulse response, the name of a [send~] to [receive~] the incoming sound from, and the name of a [catch~] to [throw~] to. Such a "helper" abstraction is useless in any other context, so I want to keep my students from using it on its own, because it might even be detrimental and confusing to try. I can tell them "don't use this." Or I can stick it in a subdirectory of the directory containing [IRconv~].pd, which is not now included in the main patch's path -- so then ideally I [declare] that path in [IRconv~] relative to [IRconv~].pd, and it should work without passing this path to the space of [IRconv~]'s parent -- this is what you advocate if I understand correctly. But, this doesn't keep a smart student from declaring the same path in the toplevel... so then I counter by changing the [declare]ation of the path to [fft-conv~] in [IRconv~] from public to private, and then it throws an error when she tries to declare that path in the parent and load [IRconv~] at the same time.
Both things can be worked around, but I think the former would be especially useful. The public/private thing isn't essential, but I think it's pedagogically more sound than not having the option. You might also want to allow abstractions not to accept their pathy inheritance, especially for resources.
Matt
On Jul 31, 2008, at 6:30 AM, Matt Barber wrote:
'relative to file location' is old school pd style, easy to
understand and together with the concept of inheritance, it covers every use
case i can think of (which implies that i would try to adapt the way i
code to pd and not vice versa).I'd almost agree with you as long as inheritance were a strong part of the model.
But...
Say I'm teaching a computer music course, and I've created a big library of commented and documented abstractions to do all kinds of neat things. I've written a script to copy the files from some global location to the user's current directory, all of them put into a directory called ./cm101-abs/ This directory is further subdivided by abstraction function: cm101-abs/control/ cm101-abs/noise/ cm101-abs/math/ etc. In order to use them the students need to either alter their search path or put in a rather lengthy [declare] which might be beyond the scope of the first semester, or as part of the script I can give them a blank file with just the [declare] statement, which they can edit as they like.
But, if Pd had a simple flag which allowed an abstraction instance to export a [declare] path to its parent, using names relative to the parent, then I can make an abstraction with just the [declare] from above, but instead of -path I use some other flag. Then all the students have to do is include an instance of that abstraction in their patches and they have access to the larger suite of abstractions. I think of this roughly as something like including a header (providing access to the interface of objects defined elsewhere). This is much simpler for the students and the teacher, and as a bonus the students learn something similar to the "include" concept.
Now, let's say I have a fairly complex dynamically patched impulse-response convolution patch called [IRconv~] using [rfft~]'s all over the place, and it has a specialized abstraction called [fft-conv~] that's loaded dynamically into the patch which has arguments specifying the $0 of the parent abstraction, the block size, its associated delay (minus block delay), the name of a [table] in the abstraction to which is written a specified set of samples from the impulse response, the name of a [send~] to [receive~] the incoming sound from, and the name of a [catch~] to [throw~] to. Such a "helper" abstraction is useless in any other context, so I want to keep my students from using it on its own, because it might even be detrimental and confusing to try. I can tell them "don't use this." Or I can stick it in a subdirectory of the directory containing [IRconv~].pd, which is not now included in the main patch's path -- so then ideally I [declare] that path in [IRconv~] relative to [IRconv~].pd, and it should work without passing this path to the space of [IRconv~]'s parent -- this is what you advocate if I understand correctly. But, this doesn't keep a smart student from declaring the same path in the toplevel... so then I counter by changing the [declare]ation of the path to [fft-conv~] in [IRconv~] from public to private, and then it throws an error when she tries to declare that path in the parent and load [IRconv~] at the same time.
Both things can be worked around, but I think the former would be especially useful. The public/private thing isn't essential, but I think it's pedagogically more sound than not having the option. You might also want to allow abstractions not to accept their pathy inheritance, especially for resources.
Now that there has been quite a bit of discussion, I think it's
really time to sketch out ideas. One good way is to make example
patches of how things might work and post them.
.hc
Matt
Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/ listinfo/pd-list
Looking at things from a more basic level, you can come up with a
more direct solution... It may sound small in theory, but it in
practice, it can change entire economies. - Amy Smith