For some reason, 'chuck' does not instantiate class static constants until there has been an instantiation of the class itself. Hans ---- static.ck ---- class Test { 3 => static int d; fun static void print() { if (d == 0) chout <= "Nope!\n"; else chout <= "Yep.\n"; } } Test.print(); Test test_; Test.print(); ---- run ---- $ chuck static.ck Nope! Yep. ----
Not necessarily a bug. Again, consistent with how Java works with classes (I
sometimes wonder if Ge got hold of the Java compiler source code cheap ;)
/Stefan
On Tue, Nov 24, 2009 at 7:51 PM, Hans Aberg
For some reason, 'chuck' does not instantiate class static constants until there has been an instantiation of the class itself.
Hans
---- static.ck ---- class Test { 3 => static int d;
fun static void print() { if (d == 0) chout <= "Nope!\n"; else chout <= "Yep.\n"; } }
Test.print(); Test test_; Test.print();
---- run ---- $ chuck static.ck Nope! Yep. ----
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
...or at least as consistent as possible, taking into account the
differences that do exist between class handling in Java and ChucK. In Java
it's stated that static members are instantiated when classes are loaded, as
part of the dynamic loading of classes - each is stored in its own file.
ChucK doesn't load classes in this way, but since Java classes are usually
loaded when they are first referenced, the effect is pretty much the same in
the two languages.
I'm guessing you want to do some kind of namespace encapsulation? It would
be a cool thing to be able to create your own equivalents of Std and Math
(maybe I'm ignorant and you already can...)
/Stefan
On Tue, Nov 24, 2009 at 10:47 PM, Stefan Blixt
Not necessarily a bug. Again, consistent with how Java works with classes (I sometimes wonder if Ge got hold of the Java compiler source code cheap ;)
/Stefan
On Tue, Nov 24, 2009 at 7:51 PM, Hans Aberg
wrote: For some reason, 'chuck' does not instantiate class static constants until there has been an instantiation of the class itself.
Hans
---- static.ck ---- class Test { 3 => static int d;
fun static void print() { if (d == 0) chout <= "Nope!\n"; else chout <= "Yep.\n"; } }
Test.print(); Test test_; Test.print();
---- run ---- $ chuck static.ck Nope! Yep. ----
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
-- Release me, insect, or I will destroy the Cosmos!
On 24 Nov 2009, at 22:47, Stefan Blixt wrote:
Not necessarily a bug. Again, consistent with how Java works with classes (I sometimes wonder if Ge got hold of the Java compiler source code cheap ;)
Is it so in Java? - In C++, they behave as global elements, and must be initialized. Hans
2009/11/24 Hans Aberg
For some reason, 'chuck' does not instantiate class static constants until there has been an instantiation of the class itself.
Writing the value to the variable is deemed part of the constructor instead of the instantiation. You could get around this using a static member function to set all such values, that way you could have static members set to default values without a class instance. I'm not completely happy with the current behaviour as two elements of a single line are treated in very different ways without this being intuitively clear. Of course it could be argued that if this bothers us we simply shouldn't do it. Kas.
On 24 Nov 2009, at 23:09, Kassen wrote:
For some reason, 'chuck' does not instantiate class static constants until there has been an instantiation of the class itself.
Writing the value to the variable is deemed part of the constructor instead of the instantiation. You could get around this using a static member function to set all such values, that way you could have static members set to default values without a class instance.
I'm not completely happy with the current behaviour as two elements of a single line are treated in very different ways without this being intuitively clear. Of course it could be argued that if this bothers us we simply shouldn't do it.
That is my worry, too: lack of intuition. It invites errors. I wrote code: class A { ... static fun float getr() { return Math.pow(2, l_); } ... } This typically causes log(2) to be re-evaluated each time pow(2, l_) is computed, assuming that it calls the C pow(). So then introduce a value for the constant log(2): class A { ... Math.log(2) => static float log2_; static fun float getr() { return Math.exp(l_*log2_); } ... } In C++ this is OK. However, in 'chuck', I have to add unrelated code: A a; otherwise the function getr() will not work. Or take the definition of log2_ it out of the class A, in which case its name is littering the global namespace. Hans
Hans;
That is my worry, too: lack of intuition. It invites errors.
I agree. The current behaviour is predictable, it could be called "expected" but I don't feel it's intuitive and I agree that it invites error. It's currently on the bugs page though it should probably be on a "open for debate and better suggestions" page instead. I feel there is a issue here but I'm not sure I have a alternative. We could have -for example- have a parser warning at this. We could also simply have attempts at setting values at definitions of static members result in a error or we could make a exception and set the value at defining the class itself. Then again; what if it's not a int being set as in; 3 => static int foo; but a function-call returning a int? This; my_fun() => static int bar; might have side effects that could be quit far-ranging. I think that if it were my call I'd suggest leaving this be and dealing with it once we get 'round to constructors. It does have uses as it is; for one thing it can tell us whether this static member is a member of a class that has a instance at all, in convenient -if hackish- shorthand. Classes and instantiation have far worse issues than this, though indeed this particular behaviour could stand documentation. Yours, Kas.
Ah, sorry Hans, I didn't read your original example properly. Static members
should be initialized the first time the class is referenced, at the latest.
/Stefan
2009/11/25 Kassen
Hans;
That is my worry, too: lack of intuition. It invites errors.
I agree. The current behaviour is predictable, it could be called "expected" but I don't feel it's intuitive and I agree that it invites error. It's currently on the bugs page though it should probably be on a "open for debate and better suggestions" page instead.
I feel there is a issue here but I'm not sure I have a alternative. We could have -for example- have a parser warning at this. We could also simply have attempts at setting values at definitions of static members result in a error or we could make a exception and set the value at defining the class itself. Then again; what if it's not a int being set as in;
3 => static int foo;
but a function-call returning a int? This;
my_fun() => static int bar;
might have side effects that could be quit far-ranging.
I think that if it were my call I'd suggest leaving this be and dealing with it once we get 'round to constructors. It does have uses as it is; for one thing it can tell us whether this static member is a member of a class that has a instance at all, in convenient -if hackish- shorthand. Classes and instantiation have far worse issues than this, though indeed this particular behaviour could stand documentation.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
Greetings! This is indeed actually a bug, not a feature! Static variables are not initialized correctly (and currently need to be explicited initialized outside the class definition). We hope to address this in the near future! All the best, Ge! On Wed, 25 Nov 2009, Stefan Blixt wrote:
Ah, sorry Hans, I didn't read your original example properly. Static members should be initialized the first time the class is referenced, at the latest. /Stefan
2009/11/25 Kassen
Hans; > That is my worry, too: lack of intuition. It invites errors.
I agree. The current behaviour is predictable, it could be called "expected" but I don't feel it's intuitive and I agree that it invites error. It's currently on the bugs page though it should probably be on a "open for debate and better suggestions" page instead.
I feel there is a issue here but I'm not sure I have a alternative. We could have -for example- have a parser warning at this. We could also simply have attempts at setting values at definitions of static members result in a error or we could make a exception and set the value at defining the class itself. Then again; what if it's not a int being set as in;
3 => static int foo;
but a function-call returning a int? This;
my_fun() => static int bar;
might have side effects that could be quit far-ranging.
I think that if it were my call I'd suggest leaving this be and dealing with it once we get 'round to constructors. It does have uses as it is; for one thing it can tell us whether this static member is a member of a class that has a instance at all, in convenient -if hackish- shorthand. Classes and instantiation have far worse issues than this, though indeed this particular behaviour could stand documentation.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
On 25 Nov 2009, at 09:05, Ge Wang wrote:
This is indeed actually a bug, not a feature! Static variables are not initialized correctly (and currently need to be explicited initialized outside the class definition). We hope to address this in the near future!
There two different concepts in play: the class body as code to be run when an element is initialized, and as a name space. The class static functions are in the latter category, and can call class static data, which then should be initialized before such use. But one could combine the two by some syntax (though T do not know if it is useful). For example, writing class A { static: 3 => int m; dynamic: 3 => static int n; ... } would indicate that m is in a static data segment and should be initialized when the class is loaded, whereas n is initialized when a class object is initialized. Then n will be initialized ever time a class object is initialized, but the idea is that this should be possible if initializing is something more complex, like opening files or creating other side effects (as Kassen suggested). But perhaps one can just use a function for this n. That is, if all static objects are initialized, one can achieve special side effects using the construct: class A { 3 => static int m; static int n; n_(); static int n_() { 3 => n; } } (though n here first gets initialized to 0). Hans
This is indeed actually a bug, not a feature! Static variables are not initialized correctly (and currently need to be explicited initialized outside the class definition). We hope to address this in the near future!
Ge, I suspect you misread the exact issue under debate here. Consider; class War { static int foo; static Gain mix; 3 => static int bar; } foo is perfectly fine, I'm sure we all agree there. mix is a a problem and that line in that form won't fly; it needs to be initialised from outside of the class. We can get around that using something like this; class War { static Gain @ mix; static fun void init() {new Gain @=> mix;} } ...that way we at least keep all of the definitions inside of the class and only need to call init() from outside. I think this is what you are refering to; this needs a fix and correct behaviour is quite clear. The problem under debate is the "bar case". bar, as a member, will be initialised at the definition of the class, it just won't have the value 3 without a instance of the class. Maybe I'm misreading your post here, and you do see the setting of the value 3 as part of initialising bar in this case? As pointed out earlier, doing so is not without questions as we may also set the value using something like; myFun() => static int bar; //or myStaticFun() => static int bar; // or myNonMemberFun() => static int bar; ...assuming all of those return a int. No problem arrises if all those do is return a int, but they may have side effects and might, in their definition, refer to non-build-in types, potentially leading to circular definitions and much more complicated demands on the order things are parsed in. Allowing this may lead to syntactically correct files that still can't be executed. I think it may be fine if we only allow static member functions (of the given class) to set such values, but that would mean a extra syntactical constraint. That said; setting static constants would be very handy in -for example- determining the length of static UGen arrays for vm-wide routing without getting into magic numbers. Right now we can't do that and such numbers can't be defined as a part of the class they belong to without instantiating the class as well. This leads to some important numbers getting defined outside of the context in which they are important, which won't win any beauty awards; for that reason I sugest currently using something like my "init()" example above as that structure really helps when returning to code weeks later. We can call the current situation a "bug" on the grounds of a line of code being only partially executed, but I don't think it's a simple bug where we can effortlessly say what should happen instead. One of my concerns is that we are very concerned with deterministic execution order in ChucK but that's no good if the execution order is very hard to predict. Phew! :-) Yours, Kas.
2009/11/25 Kassen
This is indeed actually a bug, not a feature! Static variables are not initialized correctly (and currently need to be explicited initialized outside the class definition). We hope to address this in the near future!
Ge,
I suspect you misread the exact issue under debate here. Consider;
class War { static int foo; static Gain mix; 3 => static int bar; }
foo is perfectly fine, I'm sure we all agree there. mix is a a problem and that line in that form won't fly; it needs to be initialised from outside of the class. We can get around that using something like this;
class War { static Gain @ mix; static fun void init() {new Gain @=> mix;} }
...that way we at least keep all of the definitions inside of the class and only need to call init() from outside. I think this is what you are refering to; this needs a fix and correct behaviour is quite clear.
The problem under debate is the "bar case". bar, as a member, will be initialised at the definition of the class, it just won't have the value 3 without a instance of the class. Maybe I'm misreading your post here, and you do see the setting of the value 3 as part of initialising bar in this case? As pointed out earlier, doing so is not without questions as we may also set the value using something like;
myFun() => static int bar; //or myStaticFun() => static int bar; // or myNonMemberFun() => static int bar;
...assuming all of those return a int. No problem arrises if all those do is return a int, but they may have side effects and might, in their definition, refer to non-build-in types, potentially leading to circular definitions and much more complicated demands on the order things are parsed in. Allowing this may lead to syntactically correct files that still can't be executed.
I think it may be fine if we only allow static member functions (of the given class) to set such values, but that would mean a extra syntactical constraint. That said; setting static constants would be very handy in -for example- determining the length of static UGen arrays for vm-wide routing without getting into magic numbers. Right now we can't do that and such numbers can't be defined as a part of the class they belong to without instantiating the class as well. This leads to some important numbers getting defined outside of the context in which they are important, which won't win any beauty awards; for that reason I sugest currently using something like my "init()" example above as that structure really helps when returning to code weeks later.
We can call the current situation a "bug" on the grounds of a line of code being only partially executed, but I don't think it's a simple bug where we can effortlessly say what should happen instead. One of my concerns is that we are very concerned with deterministic execution order in ChucK but that's no good if the execution order is very hard to predict.
Phew! :-)
Hey, it's a holiday here and I feel like rambling. Usually I edit posts to be as short as possible, but not today! Today I give thanks -- to words! Sorry, that's just how mailing lists work. Any dude can just come on by and dump a lot of words into a lot of inboxes whenever they feel like it. Like this. So the idiom I follow is the initialize-after one that's been mentioned a few times: class War { // declarations and instance initialization static int foo; static Gain @ mix; static int bar; } // static initialization 3 => War.bar; new Gain @=> War.mix; It's not intuitive to write (until you're used to it), but it is to read. It's clear that the static initialization happens once, right after class declaration. The static variables can be considered initialized anywhere in the class. There's no floating "War war;" to get things rolling. If it's a public class, it's likely that this is all that's in the file. If the compiler can get static initializers working, that'd be great, although having some statements execute once when the class is loaded and some when a class is instantiated is weirdly non-regular, and has issues like Kassen pointed out where it seems like you should be able to use functions depending on instance variables in static initializers due to code proximity and seeming scope. I think other compilers just check that kind of thing. That's where my rage in Java comes from, when a simple program grows to that breaking point where it's too big for a single, static main() method and I have to start making objects that Java will let me instantiate from that static safety zone that can't be inner classes because those aren't static, somehow, so I have to either make a second, non-static main or open a second file to create the classes I need as public, or fill my original class with a bunch of static methods and variables. Man, that had absolutely nothing to do with ChucK. Anyway, "static:" also suffers from this a little since to me it doesn't imply the one way "can-use" relationship between static and non-static initializers (non-static can use static, but not the other way around). Or maybe I'm a little too used to { } being the only characters that delimit scope. Unfortunately, that preference would lead to something like: class War { // class initialization int foo; Gain @ mix; 3 => int bar; instance { // instance initialization 4 => int baz; fun void screw_with_your_head() { <<< "screwing complete" >>>; } } } ... which even I don't like, but I think is illustrative and funny. Seems like a great way to make miserable the evenings of the live-coders and totally break every ChucK class ever written. Or you could pop everything left one brace level and almost be back to where we started, except with static declarations outside and before the class -- which is actually another way to handle static variables by the way, take note. Less typing to boot. int foo; new Gain @=> Gain @ mix; 3 => int bar; class War { 4 => int baz; } Well, have a good one! -- Tom Lieber http://AllTom.com/
On 26 Nov 2009, at 19:29, Tom Lieber wrote:
So the idiom I follow is the initialize-after one that's been mentioned a few times:
class War { // declarations and instance initialization static int foo; static Gain @ mix; static int bar; }
// static initialization 3 => War.bar; new Gain @=> War.mix;
It's not intuitive to write (until you're used to it), but it is to read. It's clear that the static initialization happens once, right after class declaration. The static variables can be considered initialized anywhere in the class. There's no floating "War war;" to get things rolling. If it's a public class, it's likely that this is all that's in the file.
I think chuck zero-initializes all stuff, so that would lead to a double initialization or introducing a new concept of non-initialized variable (as in C). As "static" does not have any other use outside classes, it seems me it can be treated just like introducing namespaces. So class A { 3 => static int k; fun static void f() {} ... // Non-static stuff. } would be equivalent to namespace A { 3 => static int k; fun static void f() {} } class A { ... // non-static stuff } One might introduce "static" as an {...} environment. Then the above might be written class A { static { 3 => int k; fun void f() {} } ... // Non-static stuff. } This might be a handy way to write static functions: if they are global, just move them into the class within a "static {...}" construct. And one might put in other global initialization code there, if one so likes. Hans
@Tom: nice idiom!
The first time I saw the static thing (in a discussion here or at
electro-music.com), my immediate reaction was: "why is that here? Isn't
static pretty useless in a ChucK class where you can just write a function
outside of it?" In that other language I like to talk about (starts with a
'J'), a major reason for having static members and methods is the fact that
you aren't allowed to create functions anywhere else except somewhere inside
a class definition. But the world couldn't be made completely oobject
oriented, so they introduced "static" to indicate code that lives outside
the instances of the classes.
In ChucK you principally don't need this, since you can put code anywhere.
The one thing (for me) that makes the static modifier necessary is that you
want to reference code that is in another chuck file (which I guess is what
people mostly use this for). Another minor benefit is namespace
encapsulation.
I'm feeling bold today, so I'd like to suggest to leave static parts of
classes in the state it is today for backwards compatibility (deprecate - it
really doesn't make nice bedfellows with constructor code at the top of the
class definition as shown in this discussion), fix referencing between chuck
files, and introduce a new keyword to allow folks to build namespace
hierarchies:
namespace cool {
namespace stuff {
7 => int coolClassConstant;
class CoolClass {
coolClassConstant => int coolthing;
// etc...
}
}
}
// Three days later, in another ChucK file:
cool.stuff.CoolClass coolInstance;
Again: classes really ought to only contain stuff that's actually going to
be used in objects. Static kind of works in Java, but even there it causes
confusion - there are even code standards where they dictate that you always
qualify from which class a static function is used even if it's not needed,
(i.e. AdvancedCalculalator.calculate() inside the AdvancedCalculator class)
.
/Stefan
On Thu, Nov 26, 2009 at 9:06 PM, Hans Aberg
On 26 Nov 2009, at 19:29, Tom Lieber wrote:
So the idiom I follow is the initialize-after one that's been
mentioned a few times:
class War { // declarations and instance initialization static int foo; static Gain @ mix; static int bar; }
// static initialization 3 => War.bar; new Gain @=> War.mix;
It's not intuitive to write (until you're used to it), but it is to read. It's clear that the static initialization happens once, right after class declaration. The static variables can be considered initialized anywhere in the class. There's no floating "War war;" to get things rolling. If it's a public class, it's likely that this is all that's in the file.
I think chuck zero-initializes all stuff, so that would lead to a double initialization or introducing a new concept of non-initialized variable (as in C).
As "static" does not have any other use outside classes, it seems me it can be treated just like introducing namespaces. So class A { 3 => static int k; fun static void f() {} ... // Non-static stuff. } would be equivalent to namespace A { 3 => static int k; fun static void f() {} }
class A { ... // non-static stuff }
One might introduce "static" as an {...} environment. Then the above might be written class A { static { 3 => int k; fun void f() {} } ... // Non-static stuff. }
This might be a handy way to write static functions: if they are global, just move them into the class within a "static {...}" construct. And one might put in other global initialization code there, if one so likes.
Hans
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
On 25 Nov 2009, at 06:09, Kassen wrote:
Then again; what if it's not a int being set as in;
3 => static int foo;
but a function-call returning a int? This;
my_fun() => static int bar;
might have side effects that could be quit far-ranging.
I think that if it were my call I'd suggest leaving this be and dealing with it once we get 'round to constructors. It does have uses as it is; for one thing it can tell us whether this static member is a member of a class that has a instance at all, in convenient -if hackish- shorthand. Classes and instantiation have far worse issues than this, though indeed this particular behaviour could stand documentation.
I was thinking about that situation, too. There is are two concepts: the body of a class treated as code, which should be run when the class is initialized, and as a name space. If one wants to keep both, the problem is to find a good syntax for it. The class "static" functions are just name space localizations, and may call class "static" data. Therefore, it would be confusing to not having the latter initialized when the former are called. So some new syntax might be in place. Hans
participants (5)
-
Ge Wang
-
Hans Aberg
-
Kassen
-
Stefan Blixt
-
Tom Lieber