One question I see come up with reasonable frequency is: "since REALbasic can put an enum in a module, why can't I put it into a class too?" This question is repeated for more than just enumerations -- I see it for structures, delegates, etc. It's a very reasonable question, and so I think it makes sense to spend a bit of time discussing it.
The 50,000 foot answer is: because the compiler doesn't support it! Seems kind of obvious, eh? But it's worth saying -- just because you can do something in a module doesn't mean you can do it in a class (and vice versa). Classes and modules are totally different entities, after all.
But I bet you're looking for something a little more in-depth. ;-)
Traditionally, the only thing which could declare a datatype in the compiler is a module. Modules have been able to house classes for a long time, and so it was very easy to add other datatype declarations to modules -- the support was already there for them. The data miner could locate the types to declare them to the semantic engine, the namespace search algorithm already knew where to look for types, etc. Classes have never had any such support. They could consume datatypes, but there has never been any support for classes to actually expose types themselves (either privately or publicly).
So the reason you cannot put an enumeration into a class is because an enumeration is a datatype, and classes cannot declare datatypes because there's no support in the compiler for doing that. The same argument applies to any datatype declaration: enumerations, structures, delegates, external methods, classes and interfaces. They're all type declarations, and hence not something a class can currently expose.
Now, I want to be explicit about this... the reasoning stated here is purely an explanatory snapshot in time -- the compiler may or may not be this way forever. The idea that a class can expose datatype declarations is a sensible one. So it's certainly not out of the realm of possibility that it will be able to do so in a future version of the product. The purpose of this post was simply to point out that what may appear to be an illogical omission (or even a bug, as I've seen it put) usually has very sound reasoning, even if it's not immediately apparent. Just because the concept is easy doesn't make the underlying work easy. ;-)
Sound like the sort of fundamental changes that might leave the door open to new bugs.
While I'd love to see proper encapsulation of enums in/for classes, the ability to use namespaces with public enums has made it feel much less necessary.
@Steve -- Sure, you can get the job done with datatypes in modules, but it can often feel weird. But with the ability to put a class inside of a module being exposed to the user, it allows you to write private APIs more cleanly. You can have a public class that makes use of private datatypes contained within a module, which is getting a lot closer to "clean."
I'm not certain where you got the idea that this feature would leave the door open to new bugs though, or why you think it's a fundamental change. It's not a fundamental design decision -- it's just not supported. And any code modifications have the opportunity to cause new behaviors or bugs.
Declaring an interest - a FR for enums in classes is on my watchlist. If it can be done without causing chaos, I'd be delighted.
I just assume that sort of compiler change is relatively fundamental but I suppose (depending on design) it could be mainly some extra checks in the first pass.
@Steve -- fundamental in the compiler is tricky to define. Syntax is generally not fundamental (but there are cases where it is). It's the semantics of things that already exist which is usually most fundamental. For instance, requiring everything to be explicitly New'ed, even if it's a 1st class datatype (like Integer) would be a fundamental change. Or... removing the concept of a Module would be a fundamental change. Expanding functionality is usually slightly less painful. For instance, to add types to classes means adding a few extra search paths in places. This doesn't usually affects the assumptions in other places negatively, and so it's a lot less of a problem to add. It's still work, to be sure. And there's still risk, etc. But it's not like trying to rip modules out of the language. ;-)
Adding enums, structs and the like to classes I think would be an important feature addition to REALbasic, much like delegates were, though more subtle. I get the impression that a significant portion of RB developers don't need delegates (I know I don't), but enums/structures have all sorts of uses for intermediate developers and those porting C code to RB. I've run into a few instances lately where an enum in a custom class would have really helped with a status flag. I think it's funny (and perhaps a little ridiculous) that people would consider their omission to be a bug, but I would still consider to be an illogical omission. Other languages allow this and I think any argument would end up in favor of their inclusion in RB as well. It certainly wouldn't hurt.
[Apologies if this double posts - your site is very slow for me at the moment.]
I guess my stance on this is "why aren't classes modules?" It seems like a class is just a module that defines a datatype... this is one of those things that I find somewhat irritating about RB, and why I'm just not 100% sold on it. The GUI hides a lot of details about what a class, or form, etc. really are. I tend to think it might be better to simply show users those details so they don't get confused about enums in classes or other details that syntax usually explains.
For instance, in pascal, no one would expect this to work:
type person = class gender = (gMale, gFemale); name: string; gender: enumGender; end;Simply because types don't "go" inside other types. You still have the convenience of the module level, however, to group related types together into one file/namespace. It looks like RB actually works like this, but we just can't tell from the way the IDE represents classes, at least by default. I understand that it's possible to define a class in a module - but this isn't the default way to do it, and I rather think it should be.
@Isaac -- You're right, classes and modules do seem very similar. However, to understand why they are still very different from one another, you'd have to understand the history of the language. Originally, these two concepts were significantly more different from one another in terms of what you could use them for. They're gradually heading towards similar feature sets over time, but conceptually they are still very distinct in terms of why you would use them. They will never contain the same feature set though -- because they're used in drastically different situations. For instance, a module won't ever define events. And a class won't ever define global variables.
You know, it's funny, no later than this morning, I was going through the new plugin SDK documentation, and I came across this snippet that caught my attention in the REALstructure documentation:
REALScopeProtected -- this structure is protected when defined in a class, or public when defined in a module
Is this a case of careless copy/paste, or someone jumped the gun? ;-)
LoL, copy and paste error -- but one that will be correct if and when the REALclassDefinition allows you to define structures. ;-)