Recent

Author Topic: Quick Modern Object Pascal Introduction, for Programmers  (Read 38101 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #60 on: September 05, 2016, 04:53:32 pm »
@Cyrax
He is trolling. But has made huge and valuable contributions, so he is partially forgiven :)
Our posts crossed. I made an addition.
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

BeniBela

  • Hero Member
  • *****
  • Posts: 755
    • homepage
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #61 on: September 05, 2016, 05:10:16 pm »
That's in any language. Nothing to do with Object Pascal. You know that too ;)
Look at calls through variants that's even worse.

That is why I wrote my own variants with COM-interfaces

I should have used records

And yes, my smartpointer example is a view into the very near future when that overhead is just on creation and destroy. Just try it.

I am not updating to trunk now. It is still broken from the last update



I only see one call and then a jump to right method.

Four instructions rather than one

On modern CPUs the memory-read is slower than the call



Nowadays CPU's are quite fast so there shouldn't have noticeable slowdowns on (massive) usage of interfaces.

I only found that function, because it was the slowest function of them all

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #62 on: September 05, 2016, 06:09:05 pm »
@Benibela
If that is the case, you know the drill: attach some sourcecode that reproduces the bug.

But let's focus on the fact that somebody is trying to write a book on "Modern Object Pascal" and doesn't know jack sh*t about both types of interfaces, which renders the book unusable.
Which is a pity because it has many merits. He's also very stubborn on the matter. I send him what to do in private sometime ago. He knows that. (I knew about Maciej's work at that point)
Maybe the smartpointer stuff convinces him of his evil ways/wrong doings. Otherwise I will be glad to write that chapter in an unopiniated way. I offered that too, I believe.
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

michalis

  • Full Member
  • ***
  • Posts: 107
    • Homepage
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #63 on: September 05, 2016, 09:17:20 pm »
As for the interfaces --- Thaddy, your corrections were actually applied to the article. The first COM interfaces example was changed to show the "correct" usage, based on your example. And the example with using COM interfaces through class instances was clearly marked as "dangerous, don't do it" (and moved to a lower section). Where is the factual inaccuracy in my article, which exactly sentence is wrong?

Throwing insults at everyone who doesn't agree with you doesn't help.

I guess that what you *really* want is to for me to say that "COM interfaces are better than CORBA". But I don't agree with this, I still like CORBA interfaces better. And I think I have explained my preferences very clearly. See the links, to Java and C# interfaces, which are equal to how CORBA interfaces work. If you want to convince me otherwise, give some concrete arguments. Address the arguments in my article. Explain how *all* programming languages (and CORBA interfaces in Pascal) have a bad approach to interfaces, while the COM interfaces in Pascal are the right path.

And do it with normal tone, without some baseless accusations of my person.

The incredible advantages of smartpointers do not have weight here, they do not make the disadvantages of COM interfaces disappear in any way.
« Last Edit: September 05, 2016, 11:11:08 pm by michalis »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8734
  • FPC developer.
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #64 on: September 05, 2016, 09:30:54 pm »
There is quite some overhead, because the value of the interface instance is not the same value as self of the class instance.

This goes for every pure interface because the instance might not be a known form of class

Zoran

  • Hero Member
  • *****
  • Posts: 1590
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #65 on: September 06, 2016, 12:03:31 am »
Zoran, He - and by proxy, you too - has no clue about both types of interfaces.

Okay, I don't know much.

However, why don't we finally make clear what actually interfaces are for?
I believe that the purpose of interfaces is creating abstraction for classes which do not have common ancestor. In C++ a class can have more than one parent, so interfaces aren't needed there. In Object Pascal, Java and C#, there is not multpile inheritance; that is why interfaces are introduced in these languages.

Now it seems that people think that interfaces should have other purposes. Perhaps I never understood that.
But please, let's see what tutorials say:

Please read what Delphi Basics say - http://www.delphibasics.co.uk/Article.asp?Name=Interface - under "The reason for interfaces".
Please read Delphi tutorial (on Embarcadero site) - Using Interfaces - http://docwiki.embarcadero.com/RADStudio/en/Using_Interfaces
Please read FPC Reference manual - http://www.freepascal.org/docs-html/current/ref/refse41.html

Plus, you can read what Java tutorial say - http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html

So, let me quote you again,
no clue about both types of interfaces.

Do you want to say that interfaces just are not actually what all tutorials say?
Do you want to say that their purpose should not be just to make abstraction for two or more classes which have different parents?

And, if it is their purpose (and if it isn't, then what do all these tutorials are talking about), what reference counting has to do with it?

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8734
  • FPC developer.
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #66 on: September 06, 2016, 09:38:16 am »
Okay, I don't know much.

However, why don't we finally make clear what actually interfaces are for?
I believe that the purpose of interfaces is creating abstraction for classes which do not have common ancestor. In C++ a class can have more than one parent, so interfaces aren't needed there.

(well, what about a class without a (C++) class as parent?)

The Delphi basics bit is IMHO revisionism. Interfaces were introduced for easy COM (or foreign class in general) interfacing, not for some  MI language purpose. Yes, you can (ab)use them for it, but that was not the original purpose.
« Last Edit: September 06, 2016, 09:39:51 am by marcov »

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #67 on: September 06, 2016, 09:48:23 am »
Here's a text I wrote out of sheer frustration that gives a little more insight in what interfaces are and how to use them.
There is still some work to do: GUIDS, Typelibraries, CORBA's ORB-like model, Async etc, but here you go, it is not
 complete yet, but covers the basics.

-----------------------------------------
Interface support in modern object pascal
Reference counted vs non-reference counted interfaces
-----------------------------------------
  Modern Object Pascal supports both COM and CORBA interfaces,
but actually there is a third type of interface that is native to
Object Pascal. There are many misunderstandings about interfaces so
let's try and categorise them by traits.

  The most common misconception is that you can distinguish a COM
interface from a CORBA interface because the first is reference counted
and the second is not. Let me put you out of your dreams: that is wrong!
Both COM and CORBA interfaces can be implemented without reference count.
Both COM and CORBA interfaces can be implemented with reference count.
This is to a large extend implementation detail and not a part of core
specifications, e.g. with a little thought you can implement AddRef and Release on a CORBA
interface!
From the programmers' manual:
"The {$INTERFACES} directive tells the compiler what it should take as the parent interface of an
 interface declaration which does not explicitly specify a parent interface. By default the Windows
 COM IUnknown interface is used. Other implementations of interfaces (CORBA or Java) do not
 necessarily have this interface, and for such cases, this directive can be used."

  So where does that misunderstanding come from?
Well, actually, you may not know that but is is to a certain extend
rather Object Pascal specific: Delphi implemented COM interfaces with
a default implementation that used the reference counted part of the COM
specification by default. So almost everybody that uses COM interfaces
in Object Pascal started to see COM interfaces in that light: reference
counted. And Delphi implemented CORBA interfaces without reference counting.
Let me explicitly state that was also the common practice in both camps,
it just isn't the whole of the story.
  Here we introduce the third type of interface that Object Pascal supports:
An interface type that is neither COM nor CORBA, loosly based on COM and
local to an application. It does not expose an interface to the outside
world. It does not rely on extra software or OS level support.
To make myself clear: All these three types of interface can support
reference counting or not!

So what are the most important traits of the different types of interfaces
in Object Pascal from a programmers point of view?
Well, by no means complete, but for this purpose I define them like this:
1. We have interfaces that expose themselves to the outside world
2. We have interfaces that are local to a process or application.
3. We have interfaces that are reference counted
4. We have interfaces that are not reference counted.

ad 1. requires a mechanism to talk to other processes.
      In COM that is the typelibrary. (META-language, inhibited)
      In Corba that is the interface repository. (ORB-like, centralized)

ad 2. does not need 1. but may implement it anyway, often by accident
      or lack of knowledge.

ad 3. the most important trait of reference counted interfaces is that it
      allows for automatic memory management provided correcty used.

ad 4. non-reference counted interfaces have no memory management support
      by themselves.

For the purpose of its use, let's explain how to work with reference
counted interfaces versus non-reference counted interfaces.

----------------------------
Reference counted interfaces
----------------------------
Provided you use them properly, reference counted interfaces are a bit
like strings: when an object supports a reference counted interface
it will be automatically destroyed when the reference count is zero.
But this is ONLY the case when you use them properly:
1. An object that supports a reference counted interface needs to be
   instatiated through an interface variable instead of an object variable
   for automatic memory management to work. If automatic memory management
   of an object is your goal, never instantiate such an object through
   an object or class variable.
   
   Example:
   {$INTERFACES COM}  // only partially true!
   type
     TMyobject = class(TinterfacedObject);
     
   // WRONG: memory leak, no automatic memory management occurs.
   var
     Myobject:TmyObject;
   begin
     MyObject := TMyObject.Create;
     // If you relied on automatic management, well, you have a leak!
   end. 
   
   // Better, but still wrong:
   var
     Myobject:TmyObject;
   begin
     MyObject := TMyObject.Create;
     try
     ...
     finally
       MyObject.Free;  //Yup, you do this by hand. Bit silly
     end;
   end.

So what's wrong in the second example?
Well, you have to free by hand. It is easy to forget that reference counting
does not work when you instantiate through an object variable. This is one
of the most common causes of memory leaks in an application that uses reference
counted interfaces. DON'T DO THAT! Keep that for classes and objects that do not
support a reference counted interface.

   // RIGHT, PROPER, GOOD, EXCELLENT, YOU GOT IT
   var
     Myobject:IInterface;  // instantiate through interface variable
   begin
     MyObject := TMyObject.Create as IInterface;
     // Guaranteed automatic memory management, no leaks!
     // No try/finally, nothing
   end. 
 
 So never ever forget that if you use a reference counted interface type
 you MUST instantiate through an interface variable.  NEVER through a
 class variable. Then you mix things up and you are asking for trouble.
 Pay special attention to that when you use them in your code.
 
 COM interfaces and COM-like native Object Pascal interfaces in default
 mode support reference counting by default. If you want to use any of
 these two types non-reference counted you have to do a little work: you will need to override
 the implementation of AddRef and Release:
 
   type
     TMyObject = class(TInterfacedObject)
       function _Addref:Integer;stdcall;override;
       function _Release:integer;stdcall;override;
     end;
 
     function TMyObject._AddRef:integer;
     begin
     //Keep refcount on 1
       Result := 1;
     end;
     
     function TMyObject. _Release:integer;
     begin
       Result := 1;
     end;
     
A CORBA interface does not have a refcount mechanism by default, but you can
implement it! Here's part of it. (You actually have to do a bit more, like operator support for this to work)

   {$INTERFACES CORBA}
   type
     IRefcountedCorbaInterface = interface
       function _AddRef:integer;
       function _Release:integer;
     end;
     
     TMyRefcountedCorbaObject = class(Tobject, IRefcountedCorbaInterface)
     private
       fRefcount:integer;
     public
       function _Addref:integer;virtual;
       function _Release:integer;virtual;
     end;
 
 As you can see there really is only the difference between refcounted or not,
 the difference between CORBA and COM can be made to disappear. 
 
 There's lot's more to learn about interfaces, like type libraries and
 dispatch handling but that is for a different chapter.
 I hope you have learned that:
 1. You have refcounted and non-refcounted interfaces. COM and CORBA
    can implement both.
 2. A refcounted interfaced object should be instantiated through an
    interface variable.
 3. A non-refcounted interfaced object should be instantiated through
    an object (class) variable.
 4. Never ever mix-up interface and class variables on the same object!
    That is a recipe for disaster.
 5. Object Pascal implements COM and CORBA like interfaces on ALL
    platforms.

Next time Is and As and QueryIntterface.
« Last Edit: September 06, 2016, 01:33:14 pm by Thaddy »
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #68 on: September 06, 2016, 10:43:21 am »
And, if it is their purpose (and if it isn't, then what do all these tutorials are talking about), what reference counting has to do with it?

Well. Read my write up.
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

Patito

  • New member
  • *
  • Posts: 7
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #69 on: September 06, 2016, 12:52:23 pm »
Dont ever mix up class instantiation with interface instantiation. It is still the same mistake I already reported. Is that SO difficult to understand?

Being rude doesn't help you convince me (or anyone, I suppose). So please let's discuss it in a civilized manner.

Don't let yourself get demotivated by the residual trolls.
Interfaces are an advanced topic, and there aren't many people in the pascal-world who understand the basics.

From what Thaddy wrote I think it's pretty clear, that he has no clue about the basics of interfaces.
(ignores need to mix object and interface-Reference(TComponent, ...), ignores overhead, ...)
He will never get it, and it's not worth discussing with him. (He also doesn't have much clue about strings...
and supports people that vandalize the string-type. The next big thing he will support is probably the vandalization of pascal
memory-management with some arcane ARC stuff..)

Anybody who says that 'Interfaces and Object-References' should never be mixed usually doesn't grasp any basics
about  design-patterns and polymorphism... (and has selective amnesia regarding TComponent)

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8734
  • FPC developer.
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #70 on: September 06, 2016, 01:10:37 pm »
Thaddy's writeup is mostly OK, but I'm still interested about the third type, how Delphi implements corba interfaces.

And yes, FPC's corba interface is kind of the root of iunknown, so you can manually implement iunknown (exact or not) on top of it. But the compiler will only manage it for you if the methods match iunknown (in signature and place in the IVMT)

However there is more to interfaces than refcounting, namely:

- the identity of the interface
- what the interface knows about its parent.
- how you can find an interface that belongs to an object (iow the interface tables in the object).

Besides that there are the advanced topics like "implements" and the assigning of methods to implement a signature.

Patito: this is a lazarus forum, not a design patterns and polymorphism forum.

As said you seem to assume things about interfaces (like knowing anything about its root, which is not necessarily a proper class) that the current implementation doesn't. One could make something like IInterfaceComponentReference if you want to know the root.
« Last Edit: September 06, 2016, 02:35:50 pm by marcov »

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #71 on: September 06, 2016, 01:41:29 pm »
From what Thaddy wrote I think it's pretty clear, that he has no clue about the basics of interfaces.
Take it or leave it. You are wrong.
Read the theory behind the concepts. Don't ever do that again without studying the concepts behind it thorougly.
You will look like an idiot. The same kind of idiots I am trying to prevent to write a chapter in a book that has merits but is completely, utterly wrong about the heart of the matter of interfaces.
What I wrote is vested in theory, not for screen-drawers.

@Marco
I am busy writing the remaining parts and softly correcting some of the really bolds (which were necessary in the context of this thread).
« Last Edit: September 06, 2016, 01:46:11 pm by Thaddy »
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

Zoran

  • Hero Member
  • *****
  • Posts: 1590
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #72 on: September 06, 2016, 02:09:03 pm »
Thaddy, thank you for this post!

Helps a lot, for a start... Now please let me start asking questions:

1. What is the third interface type in FPC you are talking about? You say there is the third type, but I don't see that you use it later in your post.

2. For COM type -- see the part where you are saying this:
COM interfaces and COM-like native Object Pascal interfaces in default
 mode support reference counting by default. If you want to use any of
 these two types you have to do a little work: you will need to override
 the implementation of AddRef and Release:
 
   type
     TMyObject = class(TInterfacedObject)
       function _Addref:Integer;stdcall;override;
       function _Release:integer;stdcall;override;
     end;
 
     function TMyObject._AddRef:integer;
     begin
     //Keep refcount on 1
       Result := 1;
     end;
     
     function _Release:integer;
     begin
       Result := 1;
     end;
     

What is the purpose of setting these results to 1? Did you actually mean to explain how to turn off reference counting? If so, you didn't say it, read the quoted part carefully.

EDIT: I see that meanwhile you edited what I quoted here, so yes, I assumed well, you meant how to turn off reference counting. Thanks.

3. About your first classification (first two types) -- interfaces for outside world and Interfaces for using inside the application.
I don't know much about the "outside" interfaces and I am not talking here about it. But the second usage (local application usage - this is what I think I know and how I want to use interfaces), isn't CORBA type just appropriate to use for this purpose? When you say:
ad 2. does not need 1. but may implement it anyway, often by accident
      or lack of knowledge.
What should we know to avoid implementing 1. by accident or lack of knowledge? Isn't using CORBA type (the way michalis uses it in his tutorial) just enough?

4. In part where you talk about implementing reference counting in CORBA interfaces - you mean just adding the two methods with these names will make FPC call these methods implicitly whenever in code it (correctly initialized interface variable) gets assigned to a new interface variable, and when the variable goes out of scope (just like it does automatically with COM interfaces)?
« Last Edit: September 06, 2016, 02:28:40 pm by Zoran »

hnb

  • Sr. Member
  • ****
  • Posts: 270
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #73 on: September 06, 2016, 02:22:53 pm »
COM interfaces and COM-like native Object Pascal interfaces in default
 mode support reference counting by default. If you want to use any of
 these two types non-reference counted you have to do a little work: you will need to override
 the implementation of AddRef and Release:
 
   type
     TMyObject = class(TInterfacedObject)
       function _Addref:Integer;stdcall;override;
       function _Release:integer;stdcall;override;
     end;
 
     function TMyObject._AddRef:integer;
     begin
     //Keep refcount on 1
       Result := 1;
     end;
     
     function TMyObject. _Release:integer;
     begin
       Result := 1;
     end;

That is not true. For non-reference-counted  IInterface implementation we have dedicated class: TSingletonImplementation in "Generics.Defaults" module.
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

Thaddy

  • Hero Member
  • *****
  • Posts: 10488
Re: Quick Modern Object Pascal Introduction, for Programmers
« Reply #74 on: September 06, 2016, 04:50:16 pm »

That is not true. For non-reference-counted  IInterface implementation we have dedicated class: TSingletonImplementation in "Generics.Defaults" module.
As far as I am concerned that is implementation detail, Maciej. What I wrote is perfectly in line with the theory.
Let's not get detracted from the subject. A singleton is not a non-reference counted interface, it is a completely different pattern.
The TSingletonImplementation happens to be one that avoids reference counting but on the wrong assumptions that you could not legally do that
without relying on _AddRef, and _Release. That part is nonsense.
It is like removing a wheel from a car and claim you can drive it legally with a motorcycle license because it has just three wheels  ;) (Sorry, but true)
There is a high risk he writes actual bull-shit regarding interfaces, no he has actually written bullshit already!.
That's what I am trying to prevent.
If you read his examples in his "book" , he actually assigns COM interfaces to object / class variables and then states he doesn't like them.
That's what gets me so angry. He has no clue.

I am sorry, but even you confuse theory with practice if you insist that what you suggest is the same. It isn't You know that.
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

 

TinyPortal © 2005-2018