While I've been working on the GDI+ project, I've run into a few situations where I really wish REALbasic had some language features to support what I want to do. I'm not talking about converting RB into RBC++ or anything silly like that. I'm just talking about high-level OOP constructs that I'd love to see added to the language some day.
The first one I ran into is that I'd love to see better support for default parameter values. Right now, you cannot assign a non-literal as part of the default parameter signature. So, for instance, you cannot assign a class constant, or a module constant. Normally, this isn't such a big deal -- you can simply stick in the constant value itself. However, I ran into a case with my API where I wanted the parameter type to be an enumeration. Now you're really stuck; you can't use the enumeration name, and you can't use its value. Either one gives you compile errors. That left me stuck with two choices. The first one, which happened to work out well in one instance, was to use the Optional keyword. This is akin to just assigning 0 to the default parameter. However, the second case I ran into wouldn't allow me to do that since the default value was supposed to be 3. So I was stuck making that parameter into a regular Integer, thereby losing the typesafety of enumerations.
The second issue I ran into also dealt with option parameters, but of a different type: ByRef. I would love to see a way to specify optional ByRef parameters. If the user doesn't specify the ByRef, then the value passed to the method is nil. The callee can check for the presence of the ByRef by using the Is keyword, and the caller can simply skip passing a ByRef parameter. I have a few examples of why I'd love to see this (mostly involving structures), but a simple one is this: imagine an API called MeasuresString. It takes a string and measures the bounding box around it. It also takes two optional ByRef parameters. One tells you how many character code points fit inside the bounding box without clipping, and the other tells you how many lines fit inside the bounding box without clipping. In many instances, I don't care about the data, so I'd like to leave those ByRefs off. But there are times when I would like that information as well. As an API designer, my only recourse is to make three instances of the method with different signatures. Not so bad when there's only two optional parameters. I ran into an API with five once (in a different project), which would mean you'd need 120 different combinations or so.
So enough about parameters, lets move on to scoping. One issue I've run up against over and over again with this project is the lack of the notion of "friend" support. Let me start off by saying that I hate friend support in C++ and feel it's done entirely wrong. I don't want to see that in REALbasic. What I want to see is the ability for a class to modify the scope of its members on a case-by-case basis. So, for example, let's say that ClassA and ClassB are not related except conceptually (such as a Pen and a Brush might be). As the designer of these two classes, I know that there are certain APIs which I don't want the public to have access to, such as a Handle property -- so I make it protected. But I also know that I want some of my internal classes to have access to it. For instance, I want the Pen to be able to get access to assign to the Brush handle, because the Pen is going to be constructing a new Brush via some declares. In this case, I want to be able to go into the Brush class, select the Handle property and say "this property is exposed to the Pen class." This way, the handle property is inaccessible to anything aside from Brush, a Brush subclass and Pen.
Now, you can already do this in REALbasic using a neat trick involving interfaces and protected methods (I'll leave it up to the reader to reason out the trick). But there's one case where this trick won't work, and you're left with no recourse.
Let's go back to my Pen and Brush example. Let's say that Brush has one public constructor, which takes a Color. It also has a protected constructor, since the user should not be able to make one of these things without specifying the color. Good. Now -- I want the Pen class to be able to make an instance of Brush without setting the color, because I'm going to be taking care of that an entirely different way (such as using declares). Now you're stuck. Using the interface trick, there's still no way to make an instance of Brush without specifying a color. So you have to make the Brush default Constructor public. Under the friend-like idea, this would be solved by going to Brush.Constructor and saying "the Pen class can call this as if it were public." It's a powerful concept, and there are occasional legit OOP reasons to need it.
So those are some of my current language dreams. I've got others, but I'm not ready to put them into words right now. :-P
I definitely agree whole-heartedly with the first suggestion! I recently tried to use a constant as a default parameter. Unfortunately, not only does it not work, it also fails silently on compile, without no error message at all.
But how would Optional ByRef work with primitives, like Integer or String? You can't very well check if an Integer is nil--it's always defined. You could simply pass in "0" for an Optional ByRef integer and discard any changes, but that's somewhat confusing.
RE the Friend scope: that sounds like a great idea. However, it would be of limited use unless the interface was really slick; I'm thinking about a "panel" that would be right on the property editor, beneath the definition field. The "friend" editor should be intuitively operated by both the mouse and keyboard. And descriptive error messages would also be key with a Friend implementation; otherwise new users would be frustrated when they can't figure out what they did wrong.
I'd add one more dream feature to that list: Weak refs (request #libmxqqz). A friend scope (request #phsdrjpg) would be second on my list, and using constants/enums for default values (request #ngzwwghi) is gravy.
@Adam -- you certainly can, using the Is keyword. ByRef means "this variable references that other variable over there." Nothing says "this variable" can't be nil.
Hmmm... I'm just not sure how "Is" works with primitives. For example, you can't say:
dim i as integer
if i is nil then msgbox "Nil"
You simply get a compilation error. So it would seem to require deeper changes to the language than simply allowing Optional ByRefs to be initialized to Nil, unless I'm misunderstanding something.
I won't get into the compiler changes required (they're rather mundane); you'll just have to take it on faith that it's possible for it to work, and is a sensible approach. It won't work today, but that's why it's a language dream.
I am very happy that structures will soon be able to be returned from methods (got an email about the fix a few days ago to be in R4).
The next step for me would be for structures and enums to be able to be added to Classes. It might seem weird to have a structure (which is class-like) inside a class, but it would allow declaring private datatypes only available within the class, and would be *far* more efficient than using Dictionaries to store groups of "variables".
I am starting to feel that structures are getting up to par with the other features in REALbasic.
Yeah, structs and enums inside of a class is a very sensible thing and I'd love to see that as well.
Is it a compiler thing, or mostly an IDE thing to implement?
A bit of both; the compiler needs to be able to handle scoped types (something I want anyways, so that you can have a non-global structure or enum in a module) as well as some other stuff. The IDE has to come up with a way to visually represent this sort of thing. With structures and enums, it's not so hard. But imagine a class inside of a class.
Yeah, a Class inside a Class can get a little weird.
Constant classes (i.e., classes that cannot be altered after their constructors are called) would be nice, especially if they could be passed as constants to methods or be composed inside other classes. I think I requested this feature a year or more ago.