1 Attachment(s)
Event handlers vs. base class method overrides
This is a spin-off of another thread. I detached it because it was a bit off-topic over there and could be the beginning of another interesting discussion. Also, the original thread has already been marked [RESOLVED] so some people might miss it there.
Quote:
Originally Posted by
TheGreatCthulhu
[...] .NET events are essentially just a syntactic sugar for what is in its core the Observer pattern. Events are a form of the public interface, so in that sense, handling an event is no different from calling public methods or using public properties. It can break encapsulation in the same way a method can (by directly exposing some internal aspect of the class). Semantically, events are meant to provide a notification when some state changes, so that event clients (observers) might respond to them.
For example, a button usually does not handle its own Click event, but some other, external class. The class that fires the events "knows" when the internal state changes, since (if the encapsulation principle was respected) it is the one that changes the state. In that sense, there's generally no need for a class to handle its own events, unless they come from a parent class, and no other mechanism exist.
Just as sometimes a method can break encapsulation by exposing a pointer or a .NET handle of an internal object, so that an external class might alter it's state, so can an event.
Sometimes, this behavior is desirable, sometimes it's not.
In part, it's a matter of preference, and in part is driven by the requirements.
Oops... I actually failed to observe (pun intended :)) the fact that there's a solid, generally accepted design pattern that backs MS's concept of event handlers in .NET.
My preference for overloads of the base class' On...() methods (if I already have a derived class anyway) may be a heritage from the MFC code I've written: It's pretty much the standard procedure there. Also, MSDN frequently states that overriding these methods is the preferred way to handle events in the "Notes to inheritors" section of the method documentation. I haven't found an example of the phrase on MSDN in a quick search, but IIRC it says (or at least means) that it's the preferred method if you already have a derived class. I think registering an event handler as a delegate with the base class from the derived class looks weird and not reasonable to me anyway.
The example of the button click handler you give seems to be well chosen. Unless the action to be triggered by the button is close to trivial, even in MFC the click event handler would most likely call out to some other code. And I think that, though the call to them is implemented in a much fancier way, the .NET event handlers are essentially nothing else than that code that gets called.
As already mentioned in the original thread, I have recently written a demo project for another thread which contains a class that uses (resp. is used with) a combination of both base class method overrides and event handlers. I didn't actually post the code in the other thread because it was for a homework assignment, but that was almost a month ago and so I think the homework has already been handed in in the meantime anyway. So I think I can post the code here and now as a basis for discussion.
The thread the code originally was written for contains additional discussion about the code and in particular the description of the objective of the assignment in post #1.
The code generates a draggable shape on the form in response to a button click. The shape gets destroyed when it itself is right-clicked. The shape in question is a pentagram and what's going on inside the class that draws it isn't really spectacular and doesn't matter here. So I'll just post the .h file declaring that class' interface:
Code:
// Pentagram.h
#pragma once
using namespace System;
using namespace System::Drawing;
namespace Test7
{
public ref class Pentagram
{
public:
Pentagram(Point location, float radius) : m_location(location), m_radius(radius)
{}
void SetLocation(Point location);
void Draw(Graphics ^gr);
private:
Point m_location;
float m_radius;
private:
Pentagram() {} // Disable default construction
};
}
The class that implements the actual draggable shape on the form (by using the Pentagram class above) is derived from PictureBox and is called PentagramBox:
Code:
// PentagramBox.h
#pragma once
#include "Pentagram.h"
namespace Test7
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Forms;
using namespace System::Drawing;
public ref class PentagramBox : public PictureBox
{
public:
PentagramBox(Control ^parent, Rectangle bounds);
protected:
virtual void OnPaint(PaintEventArgs ^pe) override;
virtual void OnMouseDown(MouseEventArgs ^e) override;
virtual void OnMouseUp(MouseEventArgs ^e) override;
virtual void OnMouseMove(MouseEventArgs ^e) override;
private:
Pentagram ^pent;
bool dragging;
Point lastmousepos;
private:
PentagramBox() {} // Disable default construction
};
}
Code:
// PentagramBox.cpp
#include "StdAfx.h"
#include "PentagramBox.h"
using namespace Test7;
PentagramBox::PentagramBox(Control ^parent, Rectangle bounds)
{
Parent = parent;
Bounds = bounds;
pent = gcnew Pentagram(Point(bounds.Width / 2, bounds.Height / 2), Math::Min(bounds.Width / 2, bounds.Height / 2));
dragging = false;
}
void PentagramBox::OnPaint(PaintEventArgs ^pe)
{
__super::OnPaint(pe);
pent->Draw(pe->Graphics);
}
void PentagramBox::OnMouseDown(MouseEventArgs ^e)
{
if (e->Button == Forms::MouseButtons::Left) {
dragging = true;
lastmousepos = e->Location;
}
__super::OnMouseDown(e);
}
void PentagramBox::OnMouseUp(MouseEventArgs ^e)
{
if (e->Button == Forms::MouseButtons::Left) dragging = false;
__super::OnMouseUp(e);
}
void PentagramBox::OnMouseMove(MouseEventArgs ^e)
{
if (dragging) {
Drawing::Size movevect(e->Location.X - lastmousepos.X, e->Location.Y - lastmousepos.Y);
Location += movevect;
}
__super::OnMouseMove(e);
}
You see, almost all aspects of mouse handling are done inside the class itself which provides better encapsulation. Only the right-click that destroys the draggable shape is handled in an event handler inside the form class. These are the form class' event handlers:
Code:
// Form1.cpp
#include "stdafx.h"
#include "Form1.h"
using namespace Test7;
System::Void Form1::bnCreateShape_Click(System::Object^ sender, System::EventArgs^ e)
{
pentbox = gcnew PentagramBox(this, Rectangle(10, 10, 42, 42));
pentbox->MouseClick += gcnew MouseEventHandler(this, &Form1::pentbox_MouseClick);
bnCreateShape->Enabled = false;
}
void Form1::pentbox_MouseClick(Object ^sender, MouseEventArgs ^e)
{
if (e->Button == Forms::MouseButtons::Right) {
delete pentbox;
pentbox = nullptr;
bnCreateShape->Enabled = true;
}
}
I handled that single mouse action differently because I don't feel comfortable with self-destroying objects. And even what I actually did here looks suspicious: Doesn't the event handler return to something that has already been destroyed? Probably .NET's lazy destruction and the fact that tracking handles are reference counted saved my day here. Think I better shouldn't try that in native C++...
Another reason for handling it that way, aside from being reluctant about self-destroying objets, is that the event handler also manipulates form class members that are not visible to the PentagramBox class.
Any thoughts?
I also have attached the complete project (VS 2010) to this post. Unlike the ZIP file, the project inside is named Test7, but I already have uploaded a Test7.zip in another thread, and though uploading files with the same name to different threads would even work, I wanted to make sure to avoid confusion. Of course that project also contains the code files I didn't post here.
Re: Event handlers vs. base class method overrides
I am not sure what you actually ask. But your code looks a bit strange:
delete pentbox;
C++/CLI delete operator for ref classes is mapped to Dispose method. Since PentagramBox is not disposable, this line doesn't do anything. But this shows that you don't understand completely ref class lifetime cycle and .NET references.
Regarding event handlers vs. overrides. Event handler doesn't require for client code to create derived class. Client only needs to subscribe to event. Also, events allow multiple clients to subscribe to the same event, which is impossible in inheritance model.
On the other side, inheritance allows to build projects hierarchy, when every derived class adds its own functionality (you can read such junk in every OOP book, I am not so strong in a theory...).
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Alex F
C++/CLI delete operator for ref classes is mapped to Dispose method. Since PentagramBox is not disposable, this line doesn't do anything. [...]
By "is not disposable" you mean "doesn't implement IDiaposable" (neither in the form of a "destructor" nor otherwise), don't you? Of course you're right. The member variables of PentagramBox are only value types except for the Pentagram, which in turn holds only value type members. So why should it implement IDisposable? I don't see any need for specific disposal handling here.
Control does implement IDisposable, though, and it is the direct ancestor of PictureBox from which PentagramBox is derived from. Doesn't the IDisposable implementation get inherited? (I assume PictureBox adds its own Dispose() handling to the inheritance chain but I'm not 100% sure.)
From a naive point of view: The delete statement at least superficially does what I want it to do: It instantly removes the shape from the form, so what? I don't have specific disposal requirements here and the resources held by the base classes are their own responsibility.
Quote:
[...] But this shows that you don't understand completely ref class lifetime cycle and .NET references.
You're probably right: I entered the .NET world just about half a year ago and am still learning. But IMHO .NET itself isn't completely innocent in that respect: It does quite complex things under the hood that, although the developer may actually be able to influence them, he usually doesn't need to worry about. This is quite convenient but encourages a lazy programming style one could never get away with in native C++, for instance.
Quote:
Regarding event handlers vs. overrides. Event handler doesn't require for client code to create derived class. Client only needs to subscribe to event. Also, events allow multiple clients to subscribe to the same event, which is impossible in inheritance model.
Yes, the .NET event handler concept is really convenient (yet again ;)). However, the override concept in some way allows multiple subscribers too: The event can get passed up the inheritance hierarchy by calling the base class' On...() implementation. Multiple subscribers on the same inheritance level can simply be called from the On...() implementation. And, if I understand it correctly, even the handlers registered according to the .NET event model are essentially called from the On...() implementation of the class that holds them.
In the inheritance model, an On...() implementation can simply break the chain of passing the event up the hierarchy by not calling its base class pendant. I believe in the .NET event model something similar is possible, in that one handler is able to remove another one from the event handlers collection. But that looks more complicated to me and I doubt it would (always) be good style...
Re: Event handlers vs. base class method overrides
Sorry, didn't understand your code, pentbox is PictureBox-derived, and applying delete (Dispose) to it before setting the reference to nullptr is a good programming style, which is observed among C++ (and not VB and C#) developers. Assuming, of course, that this is the last reference :)
Looking at these code fragments, I don't see how this PictureBox is displayed on the form. Generally, this should be done by adding it to the Form.Controls collection. To remove it from the form, it should be removed from this collection.
Setting last reference to nullptr actually kills .NET instance, making it candidate for garbage collection. Disposing before last reference is set to null releases unmanaged resources immediately (without waiting for GC).
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Alex F
Looking at these code fragments, I don't see how this PictureBox is displayed on the form. Generally, this should be done by adding it to the Form.Controls collection. To remove it from the form, it should be removed from this collection.
The PentagramBox contructor has a parameter of type Control ^ to which the form class passes its this pointer. This is then assigned to the (inherited) PentagramBox::Parent property. MSDN says the following about that property:
Quote:
Originally Posted by MSDN
Setting the Parent property value to nullptr removes the control from the Control::ControlCollection of its current parent control.
Although not mentioned (at least not on that page), assigning something else than nullptr to Parent does the opposite: It causes the control to add itself to the parent's Controls collection. This is quite unproblematic because it's just been given a handle to that parent. One of the Dispose() implementaions (probably the one in Control) obviously later takes care of the control removing itself from the parent's Controls collection.
Actually, I don't remember where I read that, whether I simply did it without thinking about it because this behaviour is quite natural (and was just lucky) or tried it conciously because it looks natural. :o
Quote:
Setting last reference to nullptr actually kills .NET instance, making it candidate for garbage collection. Disposing before last reference is set to null releases unmanaged resources immediately (without waiting for GC).
And the latter is certainly fatal :eek: (at least if some other code actually tries to use the object instead of just destroying the tracking handles to it). I never encountered problems with that because I handle that carefully obeying the object owner concept, most likely a habit I took over from native C++ where making the same mistake, just with a pointer instead of a tracking handle, is fatal as well. (Also, explicit deletion resp. disposal actually is rarely needed in .NET, further reducing the risk of accidents like that.)
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Alex F
I am not sure what you actually ask.
Oh, If I may clarify, since this is an thread emerged from another thread:
Eri523 just wanted to start a discussion about pros and cons of overriding On{Event} methods vs using event handlers, in derived classes.
Quote:
Originally Posted by
Alex F
Sorry, didn't understand your code, pentbox is PictureBox-derived, and applying delete (Dispose) to it before setting the reference to nullptr is a good programming style, which is observed among C++ (and not VB and C#) developers. Assuming, of course, that this is the last reference :)
What you mean "and not VB and C# developers"? In C#, after you use a class that uses unmanaged resources, and you're sure it's not going to be needed anymore, you call the Dispose() method, and set the variable to null.
Now, I don't know about the VB.NET developers, but I guess that the same guidelines apply to them. Besides, these programming practices aren't language-specific all that much.
Quote:
Originally Posted by
Eri523
Quote:
Setting last reference to nullptr actually kills .NET instance, making it candidate for garbage collection. Disposing before last reference is set to null releases unmanaged resources immediately (without waiting for GC).
And the latter is certainly fatal :eek: (at least if some other code actually tries to use the object instead of just destroying the tracking handles to it). I never encountered problems with that because I handle that carefully obeying the object owner concept, most likely a habit I took over from native C++ where making the same mistake, just with a pointer instead of a tracking handle, is fatal as well. (Also, explicit deletion resp. disposal actually is rarely needed in .NET, further reducing the risk of accidents like that.)
Well, I wouldn't say "kills", but otherwise, Alex F is right: once the last reference is released, the object becomes a candidate for the garbage collection. Most C++ developers seem to be a bit uncomfortable with this aspect of .NET: the control over the object's lifetime is taken out of their hands. But, the GC is very good at what it does. It's very efficient. Besides, this concept is at the very core of .NET: the underlying system does the cleanup. This eliminates a whole category of bugs related to native pointers and memory/resource management.
So, you would dispose of the unmanaged resources only if you're sure some other object won't use the disposed object afterward.
If not, and you don't need the object anymore, you just set it to nullptr so that the reference count drops.
If Dispose() is never called by user code, it will eventually be called by the GC.
P.S. I'll be right back, I have a comment on events.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
And the latter is certainly fatal
This is fatal if object is used after it is disposed. If you dispose the object and set its reference to nullptr, and this is the last object reference, this is absolutely OK.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
[...] Besides, this concept is at the very core of .NET: the underlying system does the cleanup. This eliminates a whole category of bugs related to native pointers and memory/resource management.
Yeah, I've already started to really appreciate this aspect of .NET. It doesn't only reduce the risk of certain bugs, it also is really convenient. :) But exactly that can be seen as a disadvantage as well: Not needing to care about object destruction (in most cases) encourages a somewhat lazy programming style that would be really bad in the major part of the world outside of .NET. I'm particularly concerned about people who learn programming on .NET and then suddenly get pushed into the cold water of native C++...
Quote:
If Dispose() is never called by user code, it will eventually be called by the GC.
Yes, and for exactly that reason I find it really handy and important to be able to call Dispose() explicitly. For instance, I have a class holding the application's config. It writes any changes to the config back out to disk in its "destructor". To enforce this, I call delete on the config object in the main form class' destructor.
Of course there would be other ways of implementing that but I find it really stringent that way.
That could'nt have been done at all if it wasn't possible to deterministically call Dispose(). I really wouldn't like to have not the slightest clue about when my config changes actually get written back. ;)
Quote:
Originally Posted by
Alex F
This is fatal if object is used after it is disposed. If you dispose the object and set its reference to nullptr, and this is the last object reference, this is absolutely OK.
Sorry, I if I wasn't clear enough about that: This is exactly what I meant and it shoud be expressed by the bracketed part of the sentence:
Quote:
Originally Posted by
Eri523
And the latter is certainly fatal :eek: (at least if some other code actually tries to use the object instead of just destroying the tracking handles to it).
Probably the smiley right in the middle of that was misplaced and messed it up.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
P.S. I'll be right back, I have a comment on events.
Obviously, I was delayed...
Quote:
Originally Posted by
Eri523
I handled that single mouse action differently because I don't feel comfortable with self-destroying objects. And even what I actually did here looks suspicious: Doesn't the event handler return to something that has already been destroyed? Probably .NET's lazy destruction and the fact that tracking handles are reference counted saved my day here. Think I better shouldn't try that in native C++...
Yeah. The OnMouseClick() protected function of PictureBox will raise the event, which essentially means invoking all the methods "stored" in the delegate (events are based on delegates). If one of those delegates happens to call Dispose() on the object, unmanaged resources will be released, but the object will continue to exist, as this is no different from any other function call. If the handler also happens to set the last reference (well, gc handle - in C# it's called a reference) to this object to nullptr, no big deal; this doesn't magically destroy the object at that very instance - just makes it eligible for garbage collection. When this happens exactly is for the GC to decide (it has it's own agenda: categorizes objects in 3 generations, according to some algorithm, etc...).
So, after the handler function returns (or after all of them return), control is returned to OnMouseClick(), when it may preform some additional logic, before it returns itself. Now, remember - unmanaged resources are disposed, and the object is generally not usable, but it still exists.
The function that receives control may perform additional tasks, and return, and so on, until the execution stops at some point for one reason or another.
Now, how the runtime determines if it's safe to perform garbage collection is irrelevant (maybe it holds an internal reference to the object while a function runs or something) - what matters is that it can figure out when it should do it.
BTW, note that when an event handler is assigned to an event, an implicit reference is created to the object that owns the handler function. Many people are not aware of this. In fact, if the only remaining reference is the one held by the event, the GC will not collect the object until the handler is removed.
Quote:
Originally Posted by
Eri523
I'm particularly concerned about people who learn programming on .NET and then suddenly get pushed into the cold water of native C++...
Those new to a .NET language (especially to C#), or those new to native C++, will often use something like "C/C++/C#" in their sentences. Of course, on both forums, such a statement is followed by a bunch of remarks about C/C++ and C# being only similar with regard to syntax, and that these are completely different languages. As such they are based on different concepts, and were made with different design goals in mind. It is important to make this distinction. C++/CLI, on the other hand, is a hybrid language, making things a bit complicated. I can imagine how a beginner might feel when confronted not only with everything C++ has to offer (which can be confusing in its own right), but also with all that blended with managed features, and all the .NET framework has to offer, altogether with rules about how to and how not to use managed and unmanaged code together.
P.S. But most of the programming best practices are in their core not language-specific, especially if these are related to design considerations. The only thing that is tricky is knowing how to apply these practices to a specific language.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
Obviously, I was delayed...
Never mind. :) I'm not really reacting in real-time at the time either. Need to catch up with some sleep deficit I accumulated but my attempts in that direction haven't been really effective yet. :o
Quote:
If the handler also happens to set the last reference (well, gc handle - in C# it's called a reference) to this object to nullptr, no big deal; this doesn't magically destroy the object at that very instance - just makes it eligible for garbage collection. When this happens exactly is for the GC to decide (it has it's own agenda: categorizes objects in 3 generations, according to some algorithm, etc...).
I wouldn't feel comfortable to rely on that, though: Any probability of success below 1.0 is called a risk. (Or, more precisely, the difference between 1.0 and the actual probability is called the risk. :rolleyes:) But what you point out later on about the delegate holding a reference to the object that is to send the event shows that's in fact no problem at all. :) I think most developers (including myself) don't always positively keep that in mind, though it can be deduced from the parameters passed to the delegate constructor.
BTW, in that respect the way I construct the mouse click event handler delegate in my code from the OP is apparently faulty:
Code:
pentbox->MouseClick += gcnew MouseEventHandler(this, &Form1::pentbox_MouseClick);
Keep in mind that this is a line in a Form1 method, not a PentagramBox one. Shouldn't that rather be the following?
Code:
pentbox->MouseClick += gcnew MouseEventHandler(pentbox, &Form1::pentbox_MouseClick);
Maybe this just isn't causing noticable problems because I don't use the sender parameter passed to the handler at all.
OTOH, the button's click handler is set up like that in Form1::InitializeComponent():
Code:
this->bnCreateShape->Click += gcnew System::EventHandler(this, &Form1::bnCreateShape_Click);
Now I'm a bit confused... :ehh:
Quote:
Now, remember - unmanaged resources are disposed, and the object is generally not usable, but it still exists.
The function that receives control may perform additional tasks, and return, and so on, until the execution stops at some point for one reason or another.
On second thought, for a similar reason self-destroying objects are even safe (to some extent) in native C++: The member function diong the self-destruction just must not access any data members of its own object after calling delete, neither directly nor indirectly. Data members get destroyed, member functions don't. Of course this design is still to be considered risky because it's easy to break during code changes, and, as usual, that risk increases with the complexity of the scenario.
Quote:
C++/CLI, on the other hand, is a hybrid language, making things a bit complicated. I can imagine how a beginner might feel when confronted not only with everything C++ has to offer (which can be confusing in its own right), but also with all that blended with managed features, and all the .NET framework has to offer, altogether with rules about how to and how not to use managed and unmanaged code together.
Yes, it's not uncommon to see beginners here happily mixing managed and unmanaged stuff without any need and then being surprised by the problems they encounter. Another indication for that confusion is that they often have problems to pick the right forum section for their post (OTOH, some of these programs are so hybrid that this decision really isn't easy to make... :rolleyes:) This is not a safe indication however, because some people simply always pick the first section in any forum due to being even too lazy to read the section descriptions (or even titles)...
BTW, the problems experienced by .NET programmers when entering the native C++ world apply to Java programmers as well in a quite similar manner...
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
Never mind. :) I'm not really reacting in real-time at the time either. Need to catch up with some sleep deficit I accumulated but my attempts in that direction haven't been really effective yet. :o
Oh, I was more talking to myself. It's a Cthulhu thing...
C:≈
[Cthulhu smileyTM]
Quote:
Originally Posted by
Eri523
I wouldn't feel comfortable to rely on that, though
Yeah, unless the docs explicitly state whether this is completely safe or not, with regard to how exactly the GC behaves.
So, with that in mind, you can either let the GC collect the object, or change the design.
Quote:
Originally Posted by
Eri523
I think most developers (including myself) don't always positively keep that in mind, though it can be deduced from the parameters passed to the delegate constructor.
BTW, in that respect the way I construct the mouse click event handler delegate in my code from the OP is apparently faulty:
Code:
pentbox->MouseClick += gcnew MouseEventHandler(this, &Form1::pentbox_MouseClick);
Keep in mind that this is a line in a Form1 method, not a PentagramBox one. Shouldn't that rather be the following?
Code:
pentbox->MouseClick += gcnew MouseEventHandler(pentbox, &Form1::pentbox_MouseClick);
Maybe this just isn't causing noticable problems because I don't use the sender parameter passed to the handler at all.
OTOH, the button's click handler is set up like that in Form1::InitializeComponent():
Code:
this->bnCreateShape->Click += gcnew System::EventHandler(this, &Form1::bnCreateShape_Click);
Now I'm a bit confused... :ehh:
Aah, but the first parameter here is not the sender object.
You pass the sender and the event arguments to the method being invoked; this is however, the delegate's constructor that takes that callback as a parameter.
Here, take a look at the constructor, as defined by the underlying system:
Quote:
Parameters
target
Type: System::Object
The object on which method is defined.
method
Type: System::String
The name of the method for which a delegate is created.
[
emphasis by me]
So, the original code is correct.
In C#, the delegate's constructor appears to take just one parameter - the method. You can even "skip" the constructor and write:
Code:
// C# code
pentbox.MouseClick += pentbox_MouseClick;
Neat, huh?
But this also means that the created dependency it's even less obvious in C#, especially to beginners.
Quote:
Originally Posted by
Eri523
BTW, the problems experienced by .NET programmers when entering the native C++ world apply to Java programmers as well in a quite similar manner...
I'm under the impression that it's significantly easier to those who transition from C# to Java, as they are similar in many respects. (And the same possibly goes for some other .NET languages as well).
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
Aah, but the first parameter here is not the sender object.
You pass the sender and the event arguments to the method being invoked; this is however, the delegate's constructor that takes that callback as a parameter.
Here, take a look at the constructor, as defined by the underlying system:
[...]
So, the original code is correct.
Fascinating! :cool: I was referring to the MouseEventHandler Delegate page on MSDN when writing this and was apparently mistaken:
Quote:
Originally Posted by MSDN
Code:
public delegate void MouseEventHandler(
Object^ sender,
MouseEventArgs^ e
)
Parameters
sender
Type: System::Object
The source of the event.
e
Type: System.Windows.Forms::MouseEventArgs
A MouseEventArgs that contains the event data.
But that seems to be wron anyway as I just noticed: The second paramneter is in no way a MouseEventArgs ^ (or I might have been on the wrong page).
This doesn't seem to be a real constructor in the usual way at all: The parent of that documentation page is the System::Windows::Forms namespace page, not that of a cass. :ehh:
Quote:
In C#, the delegate's constructor appears to take just one parameter - the method. You can even "skip" the constructor and write:
Code:
// C# code
pentbox.MouseClick += pentbox_MouseClick;
Neat, huh?
But this also means that the created dependency it's even less obvious in C#, especially to beginners.
Yes, neat and convenient indeed. But just what I say: C# does lots of things implicitly under the hood which is admittedly convenient and maybe even increases code readability, but it also often obscures what's actually going on.
Quote:
I'm under the impression that it's significantly easier to those who transition from C# to Java, as they are similar in many respects. (And the same possibly goes for some other .NET languages as well).
Well, I actually meant the transition from Java to native C++. ;) Every once a while you can find obvious examples of that in the Non-VC+ section.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
( [...] I might have been on the wrong page)
You could say that. :D
Quote:
Originally Posted by
Eri523
Code:
public delegate void MouseEventHandler(
Object^ sender,
MouseEventArgs^ e
);
[...]
This doesn't seem to be a real constructor in the usual way at all: The parent of that documentation page is the System::Windows::Forms namespace page, not that of a cass. :ehh:
That's because it's not. It's a declaration of a delegate type MouseEventHandler - kind of similar to when you declare a function pointer in C++. (It's declared in the System::Windows::Forms namespace.) However, delegates in .NET are full-blown types. As you know, all the usual .NET types implicitly derive from the Object class - and not always directly. There are types that support the language infrastructure, types that can't be used (instantiated/derived from) the normal way. MulticastDelegate is one of them; all the declared delegates implicitly derive from it (I think - some may derive from Delegate; but these are internal implementation details which are not important to us). As any other class, it provides a public interface, but it's generally of little direct use to developers.
(Just in case you missed it: I also provided a link to the MSDN page, but I've put it inside the [code][/code] section.)
Quote:
Originally Posted by
Eri523
Yes, neat and convenient indeed. But just what I say: C# does lots of things implicitly under the hood which is admittedly convenient and maybe even increases code readability, but it also often obscures what's actually going on.
On the other hand, that's not such a bad thing. This is one of the basic principles of OOP - the client doesn't need to (and shouldn't) know the internal details of the class. Similarly, it would be bad if, to code properly, you needed to know all the implementation details and intricacies of the language. C++ goes a bit against that, but as I've said - different design goals.
For example, the fact that assigning an event handler also creates a reference might be a bit obscured, but the docs and any good introductory C# (or .NET) book or course should mention it. Besides, when you think about it a bit, you realize: well, yeah - what else. Not knowing this detail isn't fatal, but knowing about it can help you create a better design and write better .NET code.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
Quote:
( [...] I might have been on the wrong page)
You could say that. :D
That's because it's not. It's a
declaration of a delegate type MouseEventHandler - kind of similar to when you declare a function pointer in C++. (It's declared in the System::Windows::Forms namespace.)
Sounds reasonable. But then what actually is the type of the expression marked in red in the snippet below?
Code:
this->bnCreateShape->Click += gcnew System::EventHandler(this, &Form1::bnCreateShape_Click);
And where on MSDN is the documentation on that and this System::EventHandler "constructor"?
Quote:
However, delegates in .NET are full-blown types. As you know, all the usual .NET types implicitly derive from the Object class - and not always directly. There are types that support the language infrastructure, types that can't be used (instantiated/derived from) the normal way. MulticastDelegate is one of them; all the declared delegates implicitly derive from it (I think - some may derive from Delegate; but these are internal implementation details which are not important to us). As any other class, it provides a public interface, but it's generally of little direct use to developers.
Yes, I've already come across these "helper types". I think System::Enum is another one of them, as well as System::ValueType. And even if it was possible to instantiate them directly, why should anyone want to do that?
Quote:
(Just in case you missed it: I also provided a link to the MSDN page, but I've put it inside the [code][/code] section.)
Don't worry, I haven't missed that link. Actually, the page it points to was the first thing I read after your post containing the link. But it looks as if that MSDN page rose more questions than it answered. A major part of what I ask in this post and my last one in this thread has been caused by that page, directly or indirectly.
Quote:
On the other hand, that's not such a bad thing. This is one of the basic principles of OOP - the client doesn't need to (and shouldn't) know the internal details of the class. Similarly, it would be bad if, to code properly, you needed to know all the implementation details and intricacies of the language.
Yes, that's encapsulation, a generally accepted and appreciated concept nowadays, and a fundamental part of the concept of many programming languages and frameworks used at the time. :)
Quote:
C++ goes a bit against that, but as I've said - different design goals.
You're talking of C++/CLI here, aren't you? Native C++ is a generally accepted language while C++/CLI still is subject to controversial discussions.
Quote:
For example, the fact that assigning an event handler also creates a reference might be a bit obscured, but the docs and any good introductory C# (or .NET) book or course should mention it. Besides, when you think about it a bit, you realize: well, yeah - what else. Not knowing this detail isn't fatal, but knowing about it can help you create a better design and write better .NET code.
Well, experienced programmers using .NET languages just as an extension of their repertoire are certainly interested in sub-surface details like that, but one of the main reasons why they are is because they know out of experience that something like that must exist somewhere. Beginners, OTOH, are IMO most likely happy with the convenience of .NET and don't read the books you're talking about, not only because they don't know the reasons why they should do that, but also because they don't know the reasons why those reasons exist...
Watch out: You're talking to an assembly language programmer! :cool: I still like to see the details, not just to simply know they're there, but also to help me to understand how the whole thing works. ;)
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
Sounds reasonable. But then what actually
is the type of the expression marked in red in the snippet below?
Code:
this->bnCreateShape->Click += gcnew System::EventHandler(this, &Form1::bnCreateShape_Click);
Good question - I've been wondering myself about that, too - as this constructor is pretty different to the one I'm used to in C# (were, aside from the shorthand syntax, you can also do it the regular way).
Now we're talking internal details of the C++/CLI language. My C++ is definitely rusty, and although I had some idea, I had to do some digging to figure it out; besides, from what I've read, this is a not-so-well-known feature anyway (well, relatively).
And I really wanted to understand all this; so, I downloaded C++/CLI specification from here (although I suspect that I already have in some obscure folder, as it might have installed with VS).
I skimmed through the chapter that overviews delegates, and I found this:
Quote:
[Chapter 8.7, pg. 20]
The constructor for a delegate needs two arguments when it is bound to a non-static member function: the first is a handle to an instance of a ref class, and the second designates the non-static member function within that ref class’s type, using the syntax of a pointer to member. The constructor for a delegate needs only one argument when it is bound to a static function, or a global- or namespace-scope function; the argument designates that function, using the syntax of a pointer to member or pointer to function, as appropriate.
Which means that what you highlighted uses the pointer-to-member-function syntax. (For non-member or static function, the '&' is optional, for member functions it is required.) In native C++, a regular function pointer and a pointer-to-member have different internal representation (as pointed out here) - I'm guessing that it's similar in C++/CLI, and that this internal data structure is somehow mapped to what the CLR expects.
BTW, this was really exciting, because while digging I've discovered something that I wasn't aware of; the thing is, native C++ pointers to member functions support polymorphism, so if the inheriting class overrides the base member, the derived implementation gets called. It made me wonder if the same goes for delegates in .NET, and my first quick tests indicate that it does! I had no idea!
Quote:
And where on MSDN is the documentation on that and this System::EventHandler "constructor"?
No clue; up until now I've only found it used in the examples, but I'm yet to see the page dedicated to it.
Quote:
Yes, I've already come across these "helper types". I think System::Enum is another one of them, as well as System::ValueType. And even if it was possible to instantiate them directly, why should anyone want to do that?
I'm not saying that one would want to - I'm just remarking that it can't be done by design. Anyway, I wouldn't call them "helper types", as these directly support .NET infrastructure - these are at the very core of the .NET type system.
Quote:
You're talking of C++/CLI here, aren't you? Native C++ is a generally accepted language while C++/CLI still is subject to controversial discussions.
I was talking both native C++ and C++/CLI, but honestly, I had native C++ in mind. Don't get me wrong: I'm not questioning C++ as a language - I'm just saying that C++ is not "hardcore" OO - as opposed to languages on the other extreme, like Smalltalk (where even classes are objects, whose class is Metaclass... o_O). For example, C# is a bit "more OO" in the sense of design, one of the reasons being the fact that it's impossible to declare a method outside of a class. C++ doesn't impose such restrictions - and it shouldn't as it would go against the core features of the language. OOP principles are really good design principles, but as you yourself noted, practical considerations (including the current evolutionary state of software and hardware) sometimes dictate that things need to be done differently in certain aspects.
Quote:
Watch out: You're talking to an assembly language programmer! :cool:
:D
Quote:
I still like to see the details, not just to simply know they're there, but also to help me to understand how the whole thing works. ;)
Oh, I like to get to know the details myself - as I've said, understanding how it works helps writing better code; what I'm saying is that sometimes the details leak out to the interface exposed to the client (I'm using the words 'interface' and 'client' in a very broad sense here) where they don't belong, thus impacting the usability of the interface.
If language syntax is the this interface used by developers (clients) to communicate to the compiler, then I might have some dissatisfaction with it.
For example, native C++ provides delete, and delete[] - this has probably been pain for anyone learning C++. But, really, why is such a distinction needed? From the perspective of the developer (client) - who cares?! Why not just one keyword - internally, the compiler could transform it to whatever it wants.
Then, take the function pointers and pointers to member functions. There is a difference, sure, internal representations are different, but again - why do I need to know this?
Or take the C++ style casting operators. To quote a page I linked to in my final post in this thread:
Quote:
There’s another reason why C++ pundits scorn C-style cast -- the same cast expression may perform two conversions at once:
Code:
const unsigned int *lp; //ptr to const unsigned int
(int *) lp; //get rid of unsigned and const at once.
And I say: so what? If the programmer made a mistake here, that’s too bad. Then again, programmers make much more mistakes by confusing delete and delete[]. Besides, what if the programmer had truly meant to use two cast operations in one expression? Should the programming language twist his arm and force him to use two different cast expressions?
Hm..., he makes a similar remark on delete/delete[].
Anyway, I'm not prepared to unconditionally defend these views - I'm just discussing them. Of course, we don't have to agree.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
And I really wanted to understand all this; so, I downloaded C++/CLI specification from
here (although I suspect that I already have in some obscure folder, as it might have installed with VS).
Wow! :eek: I had no idea there might be something like a C++/CLI standard. I always somehow presumed it was an MS homegrown thing. However, the document on that ECMA page is only about 15% the size (in bytes) of the N3126 C++0x standard draft I have here. Does it only specify the differences between standard C++ and C++/CLI?
Quote:
Which means that what you highlighted uses the pointer-to-member-function syntax. (For non-member or static function, the '&' is optional, for member functions it is required.)
Yes after some thinking I see no other option than a pointer-to-member-function too. I remember once having read something about the C++/CLI syntax for these pointers but couldn't find it again. I'm relatively sure it uses the * to designate a pointer unlike the usual C++/CLI habits. (And I think it actually is a pointer rather than a tracking handle because member functions of course are not stored in the GC heap.) I came to the conclusion that the type signature of the parameter I highlighted some posts back must at least be something similar to void (Component::*)(Object ^, MouseEventArgs ^).
While the use of * above looks justified, I think it is arguable when explicitly specifying dereferenciation of a tracking handle like in this snippet from a form load handler:
Code:
Object ^objTemp = config["windowLocation"];
if (objTemp) {
Point pnt = *dynamic_cast<Point ^>(objTemp);
if (pnt != Point(-1, -1)) Location = pnt;
}
I probably might have been able to write that more elegant using implicit unboxing but this is from one of my real apps and one of those working things I didn't change (yet).
The fact that the MulticastDelegate constructor to which you referred in post #11 takes an Object ^ along with a string holding the name of the method to call reminds me to the use of Type::InvokeMember() like in some sample code I wrote or a combination of Type::GetMethod() and MethodInfo::Invoke() I used in a module used in as of now two of my apps. Both ways of method invocation essentially take a pointer to the object to refer to (which may/must be nullptr if the method is either static, global or namespace-scope) and a string holding the name of the method to call. I have used both ways to call a late-bound method just once yet and can't decide which one actually is more convenient, more efficient or preferable for other reasons.
Quote:
In native C++, a regular function pointer and a pointer-to-member have different internal representation (as pointed out
here) - I'm guessing that it's similar in C++/CLI, and that this internal data structure is somehow mapped to what the CLR expects.
Your guess is probably right. As I already pointed out above, function pointers in C++/CLI probably need to be actual pointers while the this reference to the object the pointer is bound to needs to be a tracking handle. So in C++/CLI a pointer-to-member-function seems to be some kind of hybrid thing.
Quote:
BTW, this was really exciting, because while digging I've discovered something that I wasn't aware of; the thing is, native C++ pointers to member functions support polymorphism, so if the inheriting class overrides the base member, the derived implementation gets called. It made me wonder if the same goes for delegates in .NET, and my first quick tests indicate that it does! I had no idea!
Fascinating! :cool: I always thought of a pointer-to-member-function (in native C++) as a mere bundle of a pointer to the function code and a this pointer. I didn't have an idea either that they can do such fancy things. Now that I know of it it seems just logical, though. I never had a need for that yet (and an extremely rare need for pointers-to-member-functions at all except for creation of .NET delegates) but I feel the probability is high that sometime the day will come when it's good to know that... :)
Quote:
[...] Anyway, I wouldn't call them "helper types", as these directly support .NET infrastructure - these are at the very core of the .NET type system.
Ok, I must admit I terribly underrated them. They actually implement the vast majority of functionality of the typed that implicitly are derived from them and thus are of invaluable importance despite the fact that "normal" developers will never have to deal with them directly. Compiler developers, however, are likely to actually do that relatively frequently.
Quote:
I was talking both native C++ and C++/CLI, but honestly, I had native C++ in mind. Don't get me wrong: I'm not questioning C++ as a language - I'm just saying that C++ is not "hardcore" OO - as opposed to languages on the other extreme, like Smalltalk (where even classes are objects, whose class is Metaclass... o_O). [...] OOP principles are really good design principles, but as you yourself noted, practical considerations (including the current evolutionary state of software and hardware) sometimes dictate that things need to be done differently in certain aspects.
Oh, yes, ok... I often tend to forget about that. Although I was talking about the "pure doctrine" of encapsulation (I think that was in this very thread here) I ignored the fact that C++ itself is by no means a "pure doctrine" laguage. Probably this is mostly due to the two facts that C++ was my first encounter with OO and that I do practically all my OO-related work in C++ (well, and C++/CLI in the last few months).
I know that Smalltalk often is referred to as the flagship among the OO languages, but I think there have been some languages catching up during the last years, didn't they (whatever they are - can't think of any particular one right now)?
Quote:
If language syntax is the this interface used by developers (clients) to communicate to the compiler, then I might have some dissatisfaction with it.
To be honest, I don't understand the sentence above. Is the word "this" in it in some way related to the this pointer (in C++) or handle (in C++/CLI)?
Quote:
For example, native C++ provides delete, and delete[] - this has probably been pain for anyone learning C++. But, really, why is such a distinction needed? From the perspective of the developer (client) - who cares?! Why not just one keyword - internally, the compiler could transform it to whatever it wants.
Ok, now you really just made me doubting something I was accepting as a standing fact during the past years... :ehh: (1) Initially I was wondering myself why there's a need for two distinct variants of delete. (2) I then sometime came to the conclusion that the need for the distinction is based on the fact that the destructor only needs to be called once for a single object and more than once for an array (for non-POD types only, of course). Can't the runtime determine whether it's an array of objects or a single object (or an array comprising just a single object) from the size of a single object and the size of the memory block to be released? But what if the underlying OS can't provide the information on the size of the memory block (for some really weird reason)? (3) - and that's what just came to my mind right now: If the OS really shouldn't be able to provide the information about the size of the memory block, then how is the runtime supposed to determine for how many array elements to call the destructor in case of a delete []? :confused:
Quote:
Then, take the function pointers and pointers to member functions. There is a difference, sure, internal representations are different, but again - why do I need to know this?
I can't really come up with the syntax to call a member function via a pointer-to-member-function but wouldn't simplifying the calling syntax too much severely obscure the actual meaning of the statement? Yes, the pointer-to-member-function (in its simplest form) holds both the pointer to the object as well as to the function so there's no information needed besides the pointer and the parameters to pass. But applying maximum simplification would make the call via the pointer look like a direct call to a member function in the scope of the class the call is made from (hmmm, is there really no more compact term for that? :ehh:) or a global function (ignoring namespace-scope functions here that I consider to be globals anyway).
Quote:
Or take the C++ style casting operators.
I haven't made my peace with them yet either but I think I won't condemn them before I positively know they're not justified.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
For example, native C++ provides delete, and delete[] - this has probably been pain for anyone learning C++. But, really, why is such a distinction needed? From the perspective of the developer (client) - who cares?! Why not just one keyword - internally, the compiler could transform it to whatever it wants.
I just found this blog entry (including comments) that may interest you in this respect: http://blogs.msdn.com/b/oldnewthing/.../03/66660.aspx. It probably won't answer all your questions about this topic but may spark further discussion. (Of course this would then need to take place in one of the native C++ sections because array allocation in .NET is a completely different thing.)
I found that link in a thread in the Non-VC++ section which is dedicated to just that topic but IMO not as much to the point as the blog entry, at least not yet. Maybe joining that thread for further discussion is an option. (I have been following that thread anyway since it started - just about 24 hours ago but the thread is already comprising 16 posts.)
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
Does it only specify the differences between standard C++ and C++/CLI?
I guess - looking at the contents, you can see it mostly focuses on .NET and C++/CLI specific stuff.
Quote:
Originally Posted by
Eri523
So in C++/CLI a pointer-to-member-function seems to be some kind of hybrid thing.
Probably.
Quote:
Originally Posted by
Eri523
Fascinating! :cool: I always thought of a pointer-to-member-function (in native C++) as a mere bundle of a pointer to the function code and a this pointer. I didn't have an idea either that they can do such fancy things. Now that I know of it it seems just logical, though. I never had a need for that yet (and an extremely rare need for pointers-to-member-functions at all except for creation of .NET delegates) but I feel the probability is high that sometime the day will come when it's good to know that... :)
Another important consequence of delegates behaving this way is that you must take this behavior into account for security considerations. For example, imagine a framework that provides an extension point (not unlike Windows Forms, where you "plug-in" app-specific functionality by deriving from Form); if the imaginary framework uses a delegate internally, and this delegate points to a virtual member function, then malicious client code might cause some trouble by overriding this function in a derived class.
Quote:
Originally Posted by
Eri523
I know that Smalltalk often is referred to as the flagship among the OO languages, but I think there have been some languages catching up during the last years, didn't they (whatever they are - can't think of any particular one right now)?
Honestly, neither can I.
Quote:
Originally Posted by
Eri523
Quote:
If language syntax is the this interface used by developers (clients) to communicate to the compiler, then I might have some dissatisfaction with it.
To be honest, I don't understand the sentence above. Is the word "this" in it in some way related to the
this pointer (in C++) or handle (in C++/CLI)?
Sorry, my bad - there's an extra word in that sentence. I started writing it one way, then rephrased, but obviously didn't clean up too well.
It should've said: "If language syntax is this interface", or "If language syntax is the interface in question". So, I was referring to my previous sentence, where I said that in that particular statement I'm using the word "interface" in a very broad sense (== anything that acts as an intermediary between the client and implementation: a remote controller as an interface to the TV, a steering wheel as an interface to the car, the syntax of a programming language as an interface to the compiler, or public class members ans the interface to the class...).
With that in mind, I was not talking of anything specific to C++ or C++/CLI, but only wanted to express my dissatisfaction with interface designs that are (if only in certain aspects) influenced too much by the internal details (while I have no problem with documenting these details so that those interested can learn about them and put the knowledge to good use; but note that implementation can be subject to change).
Quote:
Originally Posted by
Eri523
[...] but wouldn't simplifying the calling syntax too much severely obscure the actual meaning of the statement?
Maybe. Then again, when you declare it, you know what it is, especially if you give it a descriptive name. I don't know - it's probably a matter of preference.
Quote:
Originally Posted by
Eri523
But applying maximum simplification would make the call via the pointer look like a direct call to a member function in the scope of the class the call is made from (hmmm, is there really no more compact term for that? :ehh:) or a global function (ignoring namespace-scope functions here that I consider to be globals anyway).
Didn't you just describe how delegates look like when invoking the referenced functions?
Quote:
Originally Posted by
Eri523
Let me reflect on a few points made there:
Quote:
Here's how the Microsoft C++ compiler manages vector allocation. Note that this is internal implementation detail, so it's subject to change at any time, but knowing this may give a better insight into why mixing scalar and vector new/delete is a bad thing.
The important thing to note is that when you do a scalar "delete p", you are telling the compiler, "p points to a single object." [...]
When you do "delete[] p", you are saying, "p points to a bunch of objects, but I'm not telling you how many."
Ant to tie this to your question:
Quote:
Originally Posted by
Eri523
(3) - and that's what just came to my mind right now: If the OS really shouldn't be able to provide the information about the size of the memory block, then how is the runtime supposed to determine for how many array elements to call the destructor in case of a delete []? :confused:
From that blog - it seems that the compiler does some extra work to handle things properly. But if it does the extra work already, than it surely can infer all that it needs from the declaration/initialization, without the programmer needing to tell it: "Hi there, Compiler! Just wanted to remind you that p points to a bunch of objects, in case you've forgotten - ;)" .
IM(H)O, the design is made more complicated without a good reason. But, I'd like to see what were the considerations that provoked the design, maybe I'm missing something.
Anyway, I'm talking about what could've been done, not about what things look like now. So, of course, a C++ programmer needs to use these the way they were meant to be used. Which brings me to that thread:
Quote:
Originally Posted by
Eri523
I found that link in
a thread in the Non-VC++ section which is dedicated to just that topic but IMO not as much to the point as the blog entry, at least not yet.
Note how the OP read and linked to that blog article, but sort of missed the point. Which somewhat reinforces my view.
Re: Event handlers vs. base class method overrides
At that thread, the OP mentioned "The C++ Programming Language" by Bjarne Stroustrup, p. 128 - which contains a sentence that talks about the way the operators we were talking about are usually implemented:
Quote:
To deallocate space allocated by new, delete and delete [] must be able to determine the size of the object allocated. This implies that an object allocated using the standard implementation of new will occupy slightly more space than a static object. Typically, one word is used to hold the object's size.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
Another important consequence of delegates behaving this way is that you must take this behavior into account for security considerations. For example, imagine a framework that provides an extension point (not unlike Windows Forms, where you "plug-in" app-specific functionality by deriving from Form); if the imaginary framework uses a delegate internally, and this delegate points to a virtual member function, then malicious client code might cause some trouble by overriding this function in a derived class.
If I saw something like that I would first assume the imaginary framework intentionally behaves like this. It is what virtual functions are made for. If I were a member of that framework's design team I would implement the virtual function as a mere call to a non-virtual member function and have the delegate point to that if I didn't want the behaviour you describe.
If that behaviour actually was unintended then I would think there's no fundametal difference to unintentionally exposing implementation details to client code in any other language.
Quote:
[...]
With that in mind, I was not talking of anything specific to C++ or C++/CLI, but only wanted to express my dissatisfaction with interface designs that are (if only in certain aspects) influenced too much by the internal details (while I have no problem with documenting these details so that those interested can learn about them and put the knowledge to good use; but note that implementation can be subject to change).
Well, going back to programming (because I don't design cars or AV appliances), I must admit that I probably also at least sometimes tend to model my interfaces too close to the implementation myself. Maybe that's because I actually have the implementation details in the back of my mind when designing the interface. So it may be a good Idea, when working in a team, to task one of the members solely with interface design, at least for some time, without giving him/her insight into implementation details at that point. That probably won't completely eliminate the problem however, simply because programmers think like programmers... ;) (I don't know whether this actually is common practice because I never worked in a team big enough to have more than one member work on a single module, interface and implementation.)
Quote:
Didn't you just describe how delegates look like when invoking the referenced functions?
Oops! :o I actually have never made a call via a delegate myself yet (always had framework classes do that for me) so I was somehow assuming they had some kind of Invoke() method. They actually have (as I interpret the first Note in the Remarks section of http://msdn.microsoft.com/en-us/library/y22acf51.aspx) but also have that functionality implemented as some sort of operator() which of course is the common way of using them. So of course you're right: A call via a delegate looks like an ordinary function call unless you clarify its meaning by some naming convention.
Quote:
From that blog - it seems that the compiler does some extra work to handle things properly. But if it does the extra work already, than it surely can infer all that it needs from the declaration/initialization, without the programmer needing to tell it: "Hi there, Compiler! Just wanted to remind you that p points to a bunch of objects, in case you've forgotten - ;)" .
IM(H)O, the design is made more complicated without a good reason. But, I'd like to see what were the considerations that provoked the design, maybe I'm missing something.
I agree that proably C++ could have been designed without the need for the [] versions of new and delete with negligible effort by employing the techniques presented in that blog article. Perhaps Stroustrup decided against that to give compiler developers the occasion to save a few bytes and microseconds, doing just that kind of nit-picking that was done in some of the blog comments.
Quote:
Note how the OP read and linked to that blog article, but sort of missed the point. Which somewhat reinforces my view.
Agreed. When implementation details like that are revealed, this is thrilling stuff for curious minds like me, but the OP apparently actually wants to make use of these details in code. IMO the whole discussion is moot anyway: Why not take the natural approach and simply use an std::vector, as already suggested by some poster relatively early in that thread? ;)
Also, thanks for the Stroustrup quote. If I actually have that passage in my copy (I have the 3rd ed., not the special ed.) there would have been little chance I wuld've actually found it because it's the German translation. On page 128 I have § 6.1.8 (A Note on Style) and § 6.2 (Operator summary) and it's cetainly not in there. From what I found on Stroustrup's pages I think I can conclude, however, that it's not too far away from that page (if it's actually there).
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
Eri523
If that behaviour actually was unintended then I would think there's no fundametal difference to unintentionally exposing implementation details to client code in any other language.
Yeah, but remember, I had no idea that delegates could do that. Maybe composition would be a better example than inheritance; but overall, now that I reflect, it was probably a not very well thought-of example altogether. In any case, it's a bad design what I was talking about, nothing really worth discussing. Just me thinking out loud about this newly discovered trait of theirs...
Quote:
Originally Posted by
Eri523
Well, going back to programming (because I don't design cars or AV appliances)
LOL, OK. But, as a side note, check out what Gamma et al. said at the start of their now famous book on Design Patterns:
Quote:
What is a Design Pattern?
Christopher Alexander says, "Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice" [AIS+77, page x]. Even though Alexander was talking about patterns in buildings and towns, what he says is true about object-oriented design patterns. Our solutions are expressed in terms of objects and interfaces instead of walls and doors, but at the core of both kinds of patterns is a solution to a problem in a context.
Everything's connected... (the X-Files theme playing in the background)
Quote:
Originally Posted by
Eri523
I must admit that I probably also at least sometimes tend to model my interfaces too close to the implementation myself.
Happens to everyone. Some software development methodologies suggest to design the interfaces and relations first, and the implementation later - but in an iterative way, where you adapt the software being developed according to ever increasing understanding of the problem domain, as you go along. The test-first approach goes nicely with that, too.
However, note that sometimes an "ideal" (whatever that means) context-free design can't be implemented properly precisely because a specific implementation environment cannot support it (for example, performance would suffer) - so implementation details sometimes must affect the design to a degree.
Quote:
Originally Posted by
Eri523
Also, thanks for the Stroustrup quote. If I actually have that passage in my copy (I have the 3rd ed., not the special ed.) there would have been little chance I wuld've actually found it because it's the German translation. On page 128 I have § 6.1.8 (A Note on Style) and § 6.2 (Operator summary) and it's cetainly not in there. From what I found on
Stroustrup's pages I think I can conclude, however, that it's not too far away from that page (if it's actually there).
Should be... 3rd ed., too: § 6.2.6.1 (Arrays), just under the example, the second sentence.
Re: Event handlers vs. base class method overrides
Quote:
Originally Posted by
TheGreatCthulhu
But, as a side note, check out what Gamma et al. said at the start of their now famous book on Design Patterns:
[...]
Really a great quote (containing another quote).
A second thought on the steering wheel analogy: This is an obvious example of legacy design. When originally introduced, the steering wheel interface was highly implementation-dependent due to limitations of those day's technology. In the meantime implementation technology has considerably evolved, even frequently resulting in situations where the steering wheel interface is placed on top of an abstraction layer called drive-by-wire. That legacy interface, however, is still used in practically all implementations, primarily simply due to long-acquired habits of billions of users. There are alternative interfaces, e.g. joysticks, available that might better fit today's implementations but yet they're not accepted by the public.
Quote:
Everything's connected... (the X-Files theme playing in the background)
:lol: :cool:
Quote:
Should be... 3rd ed., too: § 6.2.6.1 (Arrays), just under the example, the second sentence.
Found it, thanks. :) It's on page 138. However, there's a translation glitch in my copy. Translated back, it reads:
Quote:
Originally Posted by Stroustrup, TC++PL 3rd ed., German translation
To deallocate space allocated by new, new and new [] must be able to determine the size of the object allocated. This implies that an object allocated using the standard implementation of new will occupy slightly more space than a static object. Typically, one word is used to hold the object's size.
Interestingly, just in the next paragraph he also mentions std::vector. However, I don't think he does that to contrast his "subtle" mention of implementaion details in the quoted passage and the conclusions the OP of the thread over there in the Non-VC++ section pulled from that.