I was going through the documentation and I noticed there was no support for inheritance. There's also no support for closures. I also noticed that delegates compile into If-Else sequences, instead of something constant time.
I have a method to do all of these things efficiently. At least, assuming a trigger execute is efficient...
The first thing we need is a reasonable 'Dynamic' type. Dynamic stores a pointer to another type, in this case an array index, and the type that the pointer corresponds to. I created a manual compilation example, where a class with reference counting is cast to Dynamic and back:
class C
field i as int
end class
func F() as int
val x1 = new C(0)
val x2 = Dynamic.From(x1)
val x3 = x2.As(C)
val x4 = x3.i
return x4
-- compiles to --
void Halt(string message) {
int i;
TriggerDebugOutput(0, StringToText(message), true);
i = 1 / 0;
}
int[1] args_int;
trigger[100] Dynamic_field_Cleaner;
int[100] Dynamic_field_Type;
int[100] Dynamic_field_Pointer;
int[100] Dynamic_refs;
int[100] Dynamic_alloc_list;
int Dynamic_alloc_count = 0;
int Dynamic_constructor(int instance, int type, trigger cleaner) {
int me = Dynamic_alloc_list[0];
Dynamic_alloc_count += 1;
if (me == 0) { me = Dynamic_alloc_count; }
Dynamic_alloc_list[0] = Dynamic_alloc_list[me];
Dynamic_field_Type[me] = type;
Dynamic_field_Pointer[me] = instance;
Dynamic_field_Cleaner[me] = cleaner;
Dynamic_refs[me] = 0;
return me;
}
int Dynamic_method_As(int me, int type) {
if (type != Dynamic_field_Type[me]) { Halt("Type Mismatch"); }
return Dynamic_field_Pointer[me];
}
void Dynamic_destructor(int me) {
if (Dynamic_field_Cleaner[me] != null) {
args_int[0] = me;
TriggerExecute(Dynamic_field_Cleaner[me], true, true);
Dynamic_field_Cleaner[me] = null;
}
Dynamic_alloc_count -= 1;
Dynamic_alloc_list[me] = Dynamic_alloc_list[0];
Dynamic_alloc_list[0] = me;
}
void Dynamic_GainRef(int me) {
Dynamic_refs[me] += 1;
}
void Dynamic_LoseRef(int me) {
Dynamic_refs[me] -= 1;
if (Dynamic_refs[me] == 0) { Dynamic_destructor(me); }
}
int[100] C_dyn;
int[100] C_field_i;
int[100] C_refs;
int[100] C_alloc_list;
int C_alloc_count = 0;
int C_constructor(int i) {
int me = C_alloc_list[0];
C_alloc_count += 1;
if (me == 0) { me = C_alloc_count; }
C_alloc_list[0] = C_alloc_list[me];
C_field_i[me] = i;
C_refs[me] = 0;
return me;
}
void C_destructor(int me) {
if (C_dyn[me] != 0) {
Dynamic_field_Cleaner[C_dyn[me]] = null;
Dynamic_destructor(C_dyn[me]);
C_dyn[me] = 0;
}
C_alloc_count -= 1;
C_alloc_list[me] = C_alloc_list[0];
C_alloc_list[0] = me;
}void C_GainRef(int me) {
C_refs[me] += 1;
}
void C_LoseRef(int me) {
C_refs[me] -= 1;
if (C_refs[me] == 0) { C_destructor(me); }
}
trigger C_dyn_cleaner = TriggerCreate("C_dyn_cleaner_impl");
bool C_dyn_cleaner_impl(bool b1, bool b2) {
int dyn = args_int[0];
int me = Dynamic_field_Pointer[dyn];
C_dyn[me] = 0;
C_LoseRef(me);
return true;
}
int C_method_ToDynamic(int me) {
if (C_dyn[me] == 0) {
C_dyn[me] = Dynamic_constructor(me, 1, C_dyn_cleaner);
C_GainRef(me);
}
return C_dyn[me];
}
int F() {
int x1;
int x2;
int x3;
int x4;
int r;
x1 = C_constructor(23);
C_GainRef(x1);
x2 = C_method_ToDynamic(x1);
Dynamic_GainRef(x2);
x3 = Dynamic_method_As(x2, 1);
C_GainRef(x3);
x4 = C_field_i[x3];
r = x4;
C_LoseRef(x1);
Dynamic_LoseRef(x2);
C_LoseRef(x3);
return r;
}
Although I used reference counting here, it works just as well with manual destruction. The semantics here are a bit tricky, because destroying the underlying instance automatically destroys the Dynamic instance but 'destroying' the Dynamic instance at best only decreases the underlying instance's reference count.
Now that we have dynamic, we can implement delegates pretty easily. A delegate is a function pointer with its first argument optionally specified. When the delegate is invoked, cast the target instance to dynamic and store it in a global. The 'function pointer' is implemented as a trigger that calls a helper method. The helper method passes the globals into the desired method, and stores the result in a global. Then control returns to the caller, who gets the result from the global.
Example of reducing delegates to code using dynamic:
class Vector
val x as int
val y as int
func Dot(other as Vector) as int
return me.x * other.x + me.y * other.y
end class
func G() as int
Vector v = new Vector(1, -2)
Func(Vector, int) f = v.Dot
return f.Invoke(new Vector(3, 4))
-- simplifies to --
class Func_Vector_int
field static _inst as Dynamic
field static _arg1 as Vector
field static _res as int
field Pointer as trigger
field Inst as Dynamic
func Invoke(arg1 as Vector)
mytype._inst = me.inst
mytype._arg1 = arg1
TriggerExecute(me.Pointer, true, true)
return mytype._res
field static Vector_Dot_Trig = TriggerCreate("Func_Vector_int___Vector_Dot_Impl")
func static Vector_Dot_Impl(bool checkConditions, bool runActions) as bool
val inst = _inst.As(Vector)
_res = inst.Dot(_arg1)
return true
end class
func G() as int
val v = new Vector(1, -2)
val f = new Func_Vector_int(v.AsDynamic(), Func_Vector_int.Vector_Dot_Trig)
return f.Invoke(new Vector(3, 4))
Now that we have delegates, interfaces are trivial. An interface is just a class with delegate members. An instance of class C is cast to interface D by creating delegates for each of C's methods implementing D's functionality.
You got a lot of code, and very few green lines.
As I understand it. You want to implement delegates using triggers instead of if-sentences, and add support for interfaces, both of which seems doable.
I want to get the dialog part finished before moving on to something else though.
Well, I was messing around trying to get something to work. It was 'compiled' code, so I wasn't commenting it. I'll comment it below.
The basic trick is to use a trigger pointing to a custom method as your function pointer. Arguments and results are stored in globals. The 'main' argument has to be stored indirectly, because the caller does not know what type of instance owns the method it is trying to call. In the example it is stored as an array index, and the custom method knows which array to access. So:
A delegate is an indirect 'pointer' to an instance (a Dynamic) and a trigger
Callers store pointer to instance (an array index or bank key) in a common global
Callers store arguments in globals, based on their types
Callers execute the associated trigger once they have stored the argument data
Triggers point to compiler generated methods
The generated methods retrieve the instance pointer and uses it to get the instance
The generated methods retrieve the other arguments out of globals, based on their types
The generated methods pass those values into the intended function
The generated methods stor the result in a global, chosen based on its expected type
Callers pull the result from the result global, chosen based on the expected type
The 'Dynamic' code I posted is the machinery necessary to store the indirect pointers to instances. It ensures the indirect pointers don't outlive what they point to and that they count as a reference to the instance.
class C { int i; }
int F() {
C x1 = new C(0);
Dynamic x2 = Dynamic.From(x1);
C x3 = x2.As(C);
int x4 = x3.i;
return x4;
}
//////////////////////// Compiled Code ////////////////
void Halt(string message) {
int i;
TriggerDebugOutput(0, StringToText(message), true);
i = 1 / 0;
}
int[1] args_int;
//=== Dynamic Class ===
trigger[100] Dynamic_field_Cleaner; // called just before a Dynamic is destroyed (target stored in args_int[0])
int[100] Dynamic_field_Type; // the type of object pointed to by the Dynamic instance
int[100] Dynamic_field_Pointer; // points to the object, assuming you know the type-specific access stuff like which arrays contain the fields
int[100] Dynamic_refs; // reference count
int[100] Dynamic_alloc_list; // linked list of de-allocated instances, '0' is end of list
int Dynamic_alloc_count = 0; // total number of allocated instances
int Dynamic_constructor(int instance, int type, trigger cleaner) {
// allocate an unused index
int me = Dynamic_alloc_list[0];
Dynamic_alloc_count += 1;
if (me == 0) { me = Dynamic_alloc_count; }
Dynamic_alloc_list[0] = Dynamic_alloc_list[me];
// initialize values
Dynamic_field_Type[me] = type;
Dynamic_field_Pointer[me] = instance;
Dynamic_field_Cleaner[me] = cleaner;
Dynamic_refs[me] = 0;
return me;
}
/// Casts the Dynamic to the given type (note: in practice may compile to multiple methods based on pointer type)
int Dynamic_method_As(int me, int type) {
if (type != Dynamic_field_Type[me]) { Halt("Type Mismatch"); }
return Dynamic_field_Pointer[me];
}
void Dynamic_destructor(int me) {
// Fire the 'being destroyed' event, allowing holder to cleanup uncounted reference
if (Dynamic_field_Cleaner[me] != null) {
args_int[0] = me;
TriggerExecute(Dynamic_field_Cleaner[me], true, true);
Dynamic_field_Cleaner[me] = null;
}
// de-allocate index
Dynamic_alloc_count -= 1;
Dynamic_alloc_list[me] = Dynamic_alloc_list[0];
Dynamic_alloc_list[0] = me;
}
void Dynamic_GainRef(int me) {
Dynamic_refs[me] += 1;
}
void Dynamic_LoseRef(int me) {
Dynamic_refs[me] -= 1;
if (Dynamic_refs[me] == 0) { Dynamic_destructor(me); }
}
//==== C Class ====
int[100] C_dyn; // lazily-initialized cached 'dynamic instance' pointing to the C instance
int[100] C_field_i; // value stored in C
int[100] C_refs; // reference count
int[100] C_alloc_list; // linked list of available C indexes ('0' is end of list)
int C_alloc_count = 0; // number of allocated C instances
int C_constructor(int i) {
// allocate index
int me = C_alloc_list[0];
C_alloc_count += 1;
if (me == 0) { me = C_alloc_count; }
C_alloc_list[0] = C_alloc_list[me];
// initialize values
C_field_i[me] = i;
C_refs[me] = 0;
C_dyn[me] = 0;
return me;
}
void C_destructor(int me) {
// Destroy any associated dynamic instance
if (C_dyn[me] != 0) {
Dynamic_field_Cleaner[C_dyn[me]] = null; // prevent re-entrant destroy
Dynamic_destructor(C_dyn[me]);
C_dyn[me] = 0;
}
//de-allocate index
C_alloc_count -= 1;
C_alloc_list[me] = C_alloc_list[0];
C_alloc_list[0] = me;
}
void C_GainRef(int me) {
C_refs[me] += 1;
}
void C_LoseRef(int me) {
C_refs[me] -= 1;
if (C_refs[me] == 0) { C_destructor(me); }
}
// event catcher that forwards C's dynamic instance being destroyed to C losing a reference and nulling its cached dynamic
trigger C_dyn_cleaner = TriggerCreate("C_dyn_cleaner_impl");
bool C_dyn_cleaner_impl(bool b1, bool b2) {
int dyn = args_int[0];
int me = Dynamic_field_Pointer[dyn];
if (C_dyn[me] != 0) {
C_dyn[me] = 0;
C_LoseRef(me);
}
return true;
}
// 'Casts' a C instance to a Dynamic instance by creating a cached Dynamic and returning it
int C_method_ToDynamic(int me) {
if (C_dyn[me] == 0) {
C_dyn[me] = Dynamic_constructor(me, 1, C_dyn_cleaner);
C_GainRef(me);
}
return C_dyn[me];
}
// ===== F method =====
int F() {
int x1;
int x2;
int x3;
int x4;
int r;
x1 = C_constructor(23);
C_GainRef(x1);
x2 = C_method_ToDynamic(x1);
Dynamic_GainRef(x2);
x3 = Dynamic_method_As(x2, 1);
C_GainRef(x3);
x4 = C_field_i[x3];
r = x4; // result
// variables go out of scope
C_LoseRef(x1);
Dynamic_LoseRef(x2);
C_LoseRef(x3);
return r;
}
should work ?
The editor gives me errors if i make an conflict with multiple enrichments, also both "dodo" and "dodolokescake" will get shown in the tooltip if i write Bear.
So i think it should work but : "No matching Property found in enrichments" at dodolikescake
:/
Btw, why every code file in the editor is named xxx.galaxy+-. I mean there is no other ending of files. Why cant alle code files just named xxx instead xxx.galaxy+-. ( I had to use +- instead of plusplus, because this forum makes everything green after plusplus oO )
Its not a big deal, but would be nice to see, if its not that hard to change ;)
First off, this is a great tool, thanks for your contribution to the community!
I have been using your dialog designer, and love it. The only question I have is: Is there a way for me to get the galaxy++ code for the dialogs I create? I can view the code, but it wont let me copy and paste to another file. If this was possible it would be awesome as you could add additional methods and such to your dialogs.
A pretty frustrating error:
Collapsed sections, (eg if elses, /* */ comments etc.) messes up scrolling and the lines you should write on completely. The marker get positioned awkvard and writes on lines you don't want to write on.
I hope you still have some time available to work on the editor, I have seen no updates in a while.
Oh, and also, what's up with the server? I wasn't able to send an error report through the editor, and the link on the first thread seems invalid now.
Yeah, I haven't been very active on this for some time - due to christmas, exams and swtor that I wanted to try. I should be able to get some work done on it soon though - just one nasty exam left, and I don't play as much swtor now that I really only need to raid.
The server was down for maintenance for a while.. It happens from time to time.
You did a great job on that tool and compiler so far. It really helps to write better code compared to native galaxy. Hats off!
Its too bad this project isn't open source though, I surely would have contributed some patches to the repository. There are tons of exceptions which should be handled in the UI and a lot of features I personally would like to see: different build modes and preprocessor directives, a setting for the tab width, a persistent setting of sc2's executable location.
Also the compiler could really do some more code optimization, because less-optimized but often and careless used OOP otherwise results in a lot of native galaxy garbage, and as far as I know, the galaxy virtual machine doesn't care for optimization at all.
Would there per chance in the near future be added support for nested namespaces and structs/classes?
(or else, if it already exist, provide documentation of the proper syntax)
Edit:
After the latest patch(es) my project doesn't compile anymore. I know what's causing the issue, but I hope you will correct it as it was before.
This compiled in the past but does now throw the error:
"To refference a static field/property , you must type Foo.Bar" (Also fix that spelling error, it should be reference)
The problem with this is, that now I always have to write the struct name before I access the static variables when I'm inside the struct scope. It shouldn't be required. It makes sense that you need to type the scope name from outside, but not from the inside :p
Edit2:
It would be conveninent if one could copy and paste error messages as text to the clipboard, as one can't do that now.
Nested namespaces and structs/classes.. Well, it is certainly possible to implement, but it would take a lot of time to do, and it is really only a convenience. I think I will prioritize other features for now, such as being able to do reliable null checks for pointers. But progress on that is slow at the moment due to a school project.
Dahm. I'm very sorry about breaking your code.. That change was a mistake, and I will fix it for the next update.
I'll also make it possible to copy errors as text with ctrl c.
I would actually preper nestings, in particular since I want to make a conversion of the galaxy standard library into a neater scope format like in g++. The namespaces in particular or nested struct implementation would have been more desirable there.
As it is now, the implementation of:
struct Foo
{
struct Bar
{
static int Derp = 0;
}
}
Could easily be converted to Foo_Bar_Derp when compiled, instead of:
struct Foo
{
Bar bar;
}
struct Bar
{
static int Derp;
}
Not only does that create less readable code, but also a longer time to write the code, and would be compiled differently (would it not? Assuming we talk about no level of optimization right now)?
As it is now, the implementation of: struct Foo { struct Bar { static int Derp = 0; } }
Could easily be converted to Foo_Bar_Derp when compiled, instead of:
struct Foo { Bar bar; }
struct Bar { static int Derp; }
Not only does that create less readable code, but also a longer time to write the code, and would be compiled differently (would it not? Assuming we talk about no level of optimization right now)?
I'm not sure I follow your point here. As it is now, you can't nest structs/classes. Also, in the second code you would not be able to use foo.bar.Derp, since Derp is a static variable, and must be used with Bar.Derp (or, in next version, with Derp from inside Bar).
But that explanation you gave gives a better argument to have nested scopes:P What I meant with my code was:
structFoo{Barbar;}structBar{intderp;}Foofoo;
And then when being accessed, write foo.bar.derp. Though this is only a faked way of what I would want Foo.Bar.Derp to be using statics and nested scopes. And these do differ when processed and compiled.
I never meant that the first code was valid either (since it was what I was requesting as implementation, with a given example), only what I found reasonably fair that the compiler could give in return from it.
Anyway.. it seems weird to me to use a struct just to get a naming prefix - that seems to be the function of namespaces, so I think something like c# style namespaces might be better
Well actually, I thought it would be more convenient that you could introduce enums instead of having a struct with the convention of the naming prefixes (for the case I was thinking, encapsulating a block of static variables and use them more like enums.)
Also, I would not say namespaces exists just for the naming prefix - it is more often I find myself writing "using" if I want to use a namespace. But indeed, nested namespaces is something I would like either way (however, in C# as you pointed out above, you don't actually have to nest namespaces that way - what you wrote could be replaced by "namespace Foo.Bar { } "). It does really help organizing the code and make it more modular, more like packages.
Speaking of which, there seems to be a compiler error with namespaces if you exclude using the "using" keyword.
Your code above for instance, does not work properly.
If I try to access Foo.Bar.Derp, it thows the error "Unable to find anything matching Bar.Derp". If I add "using Foo" it will work, with both Foo.Bar.Derp and Bar.Derp.
Void is not a valid type for a property. I assume you mean it to be int in this case. Also, in a class, the this keyword will be a pointer to the current object. Sho you should use this->i instead of this.i.
Actually, you don't even need to write this, since you don't have any conflicting local variables, you can just write i instead of this->i.
I was going through the documentation and I noticed there was no support for inheritance. There's also no support for closures. I also noticed that delegates compile into If-Else sequences, instead of something constant time.
I have a method to do all of these things efficiently. At least, assuming a trigger execute is efficient...
The first thing we need is a reasonable 'Dynamic' type. Dynamic stores a pointer to another type, in this case an array index, and the type that the pointer corresponds to. I created a manual compilation example, where a class with reference counting is cast to Dynamic and back:
Although I used reference counting here, it works just as well with manual destruction. The semantics here are a bit tricky, because destroying the underlying instance automatically destroys the Dynamic instance but 'destroying' the Dynamic instance at best only decreases the underlying instance's reference count.
Now that we have dynamic, we can implement delegates pretty easily. A delegate is a function pointer with its first argument optionally specified. When the delegate is invoked, cast the target instance to dynamic and store it in a global. The 'function pointer' is implemented as a trigger that calls a helper method. The helper method passes the globals into the desired method, and stores the result in a global. Then control returns to the caller, who gets the result from the global.
Example of reducing delegates to code using dynamic:
Now that we have delegates, interfaces are trivial. An interface is just a class with delegate members. An instance of class C is cast to interface D by creating delegates for each of C's methods implementing D's functionality.
You got a lot of code, and very few green lines.
As I understand it. You want to implement delegates using triggers instead of if-sentences, and add support for interfaces, both of which seems doable.
I want to get the dialog part finished before moving on to something else though.
@SBeier:
Well, I was messing around trying to get something to work. It was 'compiled' code, so I wasn't commenting it. I'll comment it below.
The basic trick is to use a trigger pointing to a custom method as your function pointer. Arguments and results are stored in globals. The 'main' argument has to be stored indirectly, because the caller does not know what type of instance owns the method it is trying to call. In the example it is stored as an array index, and the custom method knows which array to access. So:
The 'Dynamic' code I posted is the machinery necessary to store the indirect pointers to instances. It ensures the indirect pointers don't outlive what they point to and that they count as a reference to the instance.
Does this mean that this :
should work ? The editor gives me errors if i make an conflict with multiple enrichments, also both "dodo" and "dodolokescake" will get shown in the tooltip if i write Bear.
So i think it should work but : "No matching Property found in enrichments" at dodolikescake :/
Btw, why every code file in the editor is named xxx.galaxy+-. I mean there is no other ending of files. Why cant alle code files just named xxx instead xxx.galaxy+-. ( I had to use +- instead of plusplus, because this forum makes everything green after plusplus oO ) Its not a big deal, but would be nice to see, if its not that hard to change ;)
Thanks for the work so far.
First off, this is a great tool, thanks for your contribution to the community!
I have been using your dialog designer, and love it. The only question I have is: Is there a way for me to get the galaxy
++
code for the dialogs I create? I can view the code, but it wont let me copy and paste to another file. If this was possible it would be awesome as you could add additional methods and such to your dialogs.wow you guys go crazy with this :)
Delegates, interface, 2 things i have hard time learning :p
A pretty frustrating error: Collapsed sections, (eg if elses, /* */ comments etc.) messes up scrolling and the lines you should write on completely. The marker get positioned awkvard and writes on lines you don't want to write on.
I hope you still have some time available to work on the editor, I have seen no updates in a while.
Oh, and also, what's up with the server? I wasn't able to send an error report through the editor, and the link on the first thread seems invalid now.
//
MexaYeah, I haven't been very active on this for some time - due to christmas, exams and swtor that I wanted to try. I should be able to get some work done on it soon though - just one nasty exam left, and I don't play as much swtor now that I really only need to raid.
The server was down for maintenance for a while.. It happens from time to time.
BIG THX for the last patch. Finaly I dont need to use compressed files with over 1000 lines :D :D It went ryl unreadable ;)
You did a great job on that tool and compiler so far. It really helps to write better code compared to native galaxy. Hats off!
Its too bad this project isn't open source though, I surely would have contributed some patches to the repository. There are tons of exceptions which should be handled in the UI and a lot of features I personally would like to see: different build modes and preprocessor directives, a setting for the tab width, a persistent setting of sc2's executable location.
Also the compiler could really do some more code optimization, because less-optimized but often and careless used OOP otherwise results in a lot of native galaxy garbage, and as far as I know, the galaxy virtual machine doesn't care for optimization at all.
Would there per chance in the near future be added support for nested namespaces and structs/classes? (or else, if it already exist, provide documentation of the proper syntax)
Edit: After the latest patch(es) my project doesn't compile anymore. I know what's causing the issue, but I hope you will correct it as it was before.
consider the following code:
This compiled in the past but does now throw the error: "To refference a static field/property , you must type Foo.Bar" (Also fix that spelling error, it should be reference) The problem with this is, that now I always have to write the struct name before I access the static variables when I'm inside the struct scope. It shouldn't be required. It makes sense that you need to type the scope name from outside, but not from the inside :p
Edit2: It would be conveninent if one could copy and paste error messages as text to the clipboard, as one can't do that now.
Nested namespaces and structs/classes.. Well, it is certainly possible to implement, but it would take a lot of time to do, and it is really only a convenience. I think I will prioritize other features for now, such as being able to do reliable null checks for pointers. But progress on that is slow at the moment due to a school project.
Dahm. I'm very sorry about breaking your code.. That change was a mistake, and I will fix it for the next update.
I'll also make it possible to copy errors as text with ctrl c.
I would actually preper nestings, in particular since I want to make a conversion of the galaxy standard library into a neater scope format like in g
++
. The namespaces in particular or nested struct implementation would have been more desirable there.As it is now, the implementation of: struct Foo { struct Bar { static int Derp = 0; } }
Could easily be converted to Foo_Bar_Derp when compiled, instead of:
struct Foo { Bar bar; }
struct Bar { static int Derp; }
Not only does that create less readable code, but also a longer time to write the code, and would be compiled differently (would it not? Assuming we talk about no level of optimization right now)?
I'm not sure I follow your point here. As it is now, you can't nest structs/classes. Also, in the second code you would not be able to use foo.bar.Derp, since Derp is a static variable, and must be used with Bar.Derp (or, in next version, with Derp from inside Bar).
Ah, my mistake.
But that explanation you gave gives a better argument to have nested scopes:P What I meant with my code was:
And then when being accessed, write foo.bar.derp. Though this is only a faked way of what I would want Foo.Bar.Derp to be using statics and nested scopes. And these do differ when processed and compiled.
I never meant that the first code was valid either (since it was what I was requesting as implementation, with a given example), only what I found reasonably fair that the compiler could give in return from it.
Actually, as it is, you can write
To get your Foo.Bar.Derp.
Anyway.. it seems weird to me to use a struct just to get a naming prefix - that seems to be the function of namespaces, so I think something like c# style namespaces might be better
Well actually, I thought it would be more convenient that you could introduce enums instead of having a struct with the convention of the naming prefixes (for the case I was thinking, encapsulating a block of static variables and use them more like enums.)
Also, I would not say namespaces exists just for the naming prefix - it is more often I find myself writing "using" if I want to use a namespace. But indeed, nested namespaces is something I would like either way (however, in C# as you pointed out above, you don't actually have to nest namespaces that way - what you wrote could be replaced by "namespace Foo.Bar { } "). It does really help organizing the code and make it more modular, more like packages.
Speaking of which, there seems to be a compiler error with namespaces if you exclude using the "using" keyword. Your code above for instance, does not work properly.
If I try to access Foo.Bar.Derp, it thows the error "Unable to find anything matching Bar.Derp". If I add "using Foo" it will work, with both Foo.Bar.Derp and Bar.Derp.
Hey can u help me? I dont understand what here is wrong:
error: [7, 21]: expecting "("
Void is not a valid type for a property. I assume you mean it to be int in this case. Also, in a class, the this keyword will be a pointer to the current object. Sho you should use this->i instead of this.i.
Actually, you don't even need to write this, since you don't have any conflicting local variables, you can just write i instead of this->i.
SBeier Thx. In AS3.0 easy to understand: function set/get FUNC():void/return -> setter or getter
Sorry my eng.
And one more problem whit properties of class; create class:
error: must be a struct, class or something which is enriched.
And what there is wrong?