Recent

Author Topic: Good explaination of how interfaces work.  (Read 1151 times)

Thaiblood

  • Newbie
  • Posts: 1
Good explaination of how interfaces work.
« on: October 02, 2022, 04:38:16 am »
Hi
I have looked and looked and i cannot figure out how to use interfaces. I have recently taugh myself the Go programming language and i think i have the gist of what an interface is supposed to do. But non of the examples i try for pascal work. Some of the examples say that i must specify a unique id thing. Why is that neccesary and how do i obtain one for the interfaces that i want to make?

So to sum up my question:

1. Explain to me how to use interfaces in freepascal with an example.
2. Is the unique id thing strictly neccesary and what is it's purpose?
3. If the unique id thing is neccesary, then how do i obtain one for the interfaces i am creating.
4. If you know, then also explain to me the differences from freepascal's interfaces and Golang's interfaces.

Thank
 
« Last Edit: October 02, 2022, 05:46:15 pm by marcov »

dje

  • Full Member
  • ***
  • Posts: 124
Re: Good explaination of how interfaces work.
« Reply #1 on: October 02, 2022, 05:16:48 am »
1. Explain to me how to use interfaces in freepascal with an example.

Google FreePascal interfaces (or Delphi interfaces). There is a ton of information online:
https://wiki.lazarus.freepascal.org/Understanding_Interfaces
https://wiki.lazarus.freepascal.org/How_To_Use_Interfaces

2. Is the unique id thing strictly neccesary and what is it's purpose?
No. Its for COM programming. "It is used to enable inter-process communication object creation in a large range of programming languages"
https://en.m.wikipedia.org/wiki/Component_Object_Model
Quote
COM programmers build their software using COM-aware components. Different component types are identified by class IDs (CLSIDs), which are Globally Unique Identifiers (GUIDs). Each COM component exposes its functionality through one or more interfaces. The different interfaces supported by a component are distinguished from each other using interface IDs (IIDs), which are GUIDs too. COM interfaces have bindings in several languages, such as C, C++, Visual Basic, Delphi, Python[10][11] and several of the scripting languages implemented on the Windows platform. All access to components is done through the methods of the interfaces. This allows techniques such as inter-process, or even inter-computer programming (the latter using the support of DCOM).
3. If the unique id thing is neccesary, then how do i obtain one for the interfaces i am creating.
Ctrl+Shift+G

4. If you know, then also explain to me the differences from freepascal's interfaces and Golang's interfaces.
Unsure. It looks like Go doesn't have classes, but uses "interfaces", which seems to be an abstract type. Maybe its similar to C++ pure classes, or Pascals abstract classes.

I wouldn't assume they are the same. In general, interfaces are not 100% needed for general FreePascal programming, so I would keep away from them until you have learn't and exhausted all the other Object Pascal language features.

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 782
Re: Good explaination of how interfaces work.
« Reply #2 on: October 02, 2022, 08:02:31 am »
No. Its for COM programming. "It is used to enable inter-process communication object creation in a large range of programming languages"
https://en.m.wikipedia.org/wiki/Component_Object_Model
Not necessary. GUID is required for IS and AS operators to work. And these two operators are required for virtual casting to work.

I guess, it's better to read this article.
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5569
Re: Good explaination of how interfaces work.
« Reply #3 on: October 02, 2022, 09:01:54 am »
I guess, it's better to read this article.

Well, as a "Classical Pascal" guy I think of myself as being in much the same boat as OP. And every time I try to get to grips with interfaces I come up against something like (from the wiki article cited above):

"You should understand, that there are two kinds of interfaces. ... 1) Interfaces as tool to implement multiple inheritance, as they work in some other languages, like Java 2) OLE/COM interfaces as Windows-specific language-independent way to implement OOP."

But the code example right at the top of that wiki page refers to CORBA, which is neither (1) nor (2). At that point I give up. Again.

It might possibly be safe to say something like "In a component-based system, each underlying component is described by an interface, sometimes with an associated GUID. At the application programming level, multiple interfaces can be grouped together to provide the functionality for an object." But on a system that doesn't have all its functionality in external components, it leaves me wondering what all the fuss is about.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 782
Re: Good explaination of how interfaces work.
« Reply #4 on: October 02, 2022, 09:47:44 am »
Well, as a "Classical Pascal" guy I think of myself as being in much the same boat as OP. And every time I try to get to grips with interfaces I come up against something like (from the wiki article cited above):

"You should understand, that there are two kinds of interfaces. ... 1) Interfaces as tool to implement multiple inheritance, as they work in some other languages, like Java 2) OLE/COM interfaces as Windows-specific language-independent way to implement OOP."

But the code example right at the top of that wiki page refers to CORBA, which is neither (1) nor (2). At that point I give up. Again.

It might possibly be safe to say something like "In a component-based system, each underlying component is described by an interface, sometimes with an associated GUID. At the application programming level, multiple interfaces can be grouped together to provide the functionality for an object." But on a system that doesn't have all its functionality in external components, it leaves me wondering what all the fuss is about.

MarkMLl
Well, it's actually not my article, so it isn't my example. It's just copy-paste of my post from some other thread about interfaces. Yeah, reference counting is nice thing, but it's not mandatory. One can control object's life time by himself, if he desires to do it.

Inheritance - is confusing thing. It's called inheritance and it's syntax looks like inheritance (TChild = class(TParent)  looks like it's TChild <- TParent), but it's actually two-way process, i.e. TChild <-> TParent. It's both inheritance (child inherits something from parent) and polymorphism (child implements some parent's features). And there is one thing about inheritance. While multiple inheritance is considered to be bad thing, multiple polymorphism - isn't. Interfaces are just some way to implement "lite" version of multiple polymorphism, i.e. to implement multiple polymorphism without actually implementing multiple inheritance.

And multiple polymorphism is needed, when objects should behave differently in different situations. For example TList can be both TCountable and TEnumerable. It's very powerful tool, as it removes restrictions of static typification.

P.S. My way to interfaces was long and hard. As always, one starts to understand, for what purpose certain tools are needed, only when he faces so complex task, that is very hard to implement without such tools. My task was - to reuse TChild's code instead of copy-pasting it to TModifiedChild:
Code: Pascal  [Select][+][-]
  1. TParent = class;abstract;
  2.  
  3. TChild = class(TParent);
  4.  
  5. TModifiedParent = class(TParent);abstract;
  6.  
  7. TModifiedChild = class(TChild, TModifiedParent);
  8.  
« Last Edit: October 02, 2022, 10:06:33 am by Mr.Madguy »
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5569
Re: Good explaination of how interfaces work.
« Reply #5 on: October 02, 2022, 10:11:35 am »
Well, it's actually not my article, so it isn't my example. It's just copy-paste of my post from some other thread about interfaces. Yeah, reference counting is nice thing, but it's not mandatory. One can control object's life time by himself, if he desires to do it.

Don't worry: I'm definitely not blaming you. But like so many things these days the article is written by somebody who knows what he's explaining, not by somebody who knows how to explain it (if you get my drift).

I've just been taking a look at the CORBA article on Wp (and I've been struggling to get my head around the applicability of this stuff since CORBA, IDL etc. came out in the early '90s). Neither article starts off with a succinct explanation of what an external component might encapsulate, why one can benefit from using that external component, and the reasons that going through something like CORBA is a benefit (e.g. data reorganisation determined by what's in the IDL).

So while I appreciate that while it can be used as a sort of "super RPC" remotely, and that locally it's an alternative to class multiple inheritance, generally speaking I don't see what the fuss is about.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 782
Re: Good explaination of how interfaces work.
« Reply #6 on: October 02, 2022, 10:32:23 am »
Don't worry: I'm definitely not blaming you. But like so many things these days the article is written by somebody who knows what he's explaining, not by somebody who knows how to explain it (if you get my drift).

I've just been taking a look at the CORBA article on Wp (and I've been struggling to get my head around the applicability of this stuff since CORBA, IDL etc. came out in the early '90s). Neither article starts off with a succinct explanation of what an external component might encapsulate, why one can benefit from using that external component, and the reasons that going through something like CORBA is a benefit (e.g. data reorganisation determined by what's in the IDL).

So while I appreciate that while it can be used as a sort of "super RPC" remotely, and that locally it's an alternative to class multiple inheritance, generally speaking I don't see what the fuss is about.

MarkMLl
Everybody comes to interfaces sooner or later, as complexity of his tasks grows more and more. It's both good way to implement more complex relations between objects, than standard OOP allows, and to automatically manage objects' life time in order to avoid memory leaks and "use after free" errors without using safe languages, like Rust. And at the end separating declaration from implementation - is actually good practice. Because one can never know, if he will need to split his program into several modules or not.

P.S. And of course RPC. But I don't treat it as major reason, why interfaces appeared. It's just nice bonus.
« Last Edit: October 02, 2022, 10:43:36 am by Mr.Madguy »
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5569
Re: Good explaination of how interfaces work.
« Reply #7 on: October 02, 2022, 10:43:26 am »
Everybody comes to interfaces sooner or later, as complexity of his tasks grows more and more. It's both good way to implement more complex relations between objects, than standard OOP allows, and to automatically manage objects' life time in order to avoid memory leaks and "use after free" errors without using safe languages, like Rust. And at the end separating declaration from implementation - is actually good practice. Because one can never know, if he will need to split his program into several modules or not.

Well, I've been using Delphi etc. for substantially more than 20 years, and from my POV there are far more pressing omissions in the language etc. than this addresses.

I mean, if somebody could demonstrate that this provided a better way of getting at a remote database than ODBC, or a better way of interfacing with a remote user than X11 or Wayland, then I think there would be compelling reasons for promoting it.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 782
Re: Good explaination of how interfaces work.
« Reply #8 on: October 02, 2022, 10:56:49 am »
Well, I've been using Delphi etc. for substantially more than 20 years, and from my POV there are far more pressing omissions in the language etc. than this addresses.

I mean, if somebody could demonstrate that this provided a better way of getting at a remote database than ODBC, or a better way of interfacing with a remote user than X11 or Wayland, then I think there would be compelling reasons for promoting it.

MarkMLl
Delphi/FPC can be turned into pseudo-scripted language via: 1) Wrapping all simple types into objects to make them type-compatible (optional) 2) Using interfaces for everything in order to achieve auto object life time management 3) Making good data management library, i.e. implement lists, dictionaries, stacks, queues, etc. Simply because data management - is very common goal. Such as "For number-letter pairs make list of all letters, that has the same number". It's just way too tedious to always rewrite such code from scratch. It should be standard.

And again. Interfaces aren't about RPC only. It's just nice bonus. It's all about protocols. Nothing stops you from wrapping X or Wayland into interfaces. Question is - is it needed?
« Last Edit: October 02, 2022, 10:59:42 am by Mr.Madguy »
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

Warfley

  • Hero Member
  • *****
  • Posts: 941
Re: Good explaination of how interfaces work.
« Reply #9 on: October 02, 2022, 11:07:39 am »
First of all, forgett about multi inheritance, this most cerntainly only complicates it (I don't know why people think that this is a good explaination, inheritance in itself is much more complex to expalin than interfaces).

To make it simple, at it's core, an interface is very simple, it is a promise that the class you are writing contains a certain set of functions (and properties). Then using this interface in your code is equivalent to saying: "I don't care what kind of type something is as long as it holds to the promise made in the interface".

For example:
Code: Pascal  [Select][+][-]
  1. type
  2.   IPrintable = interface
  3.   function ToString: String;
  4.   end;
Any class that uses this interface promises that there will be a "ToString" function. So for example, if you write a logger, which shall log whenever some class get's created, the logger does not care what class that is, as long as it can write it to the log file. Therefore the logger would have something like this:
Code: Pascal  [Select][+][-]
  1. procedure TLogger.LogClassCreation(CreatedClass: IPrintable);
  2. begin
  3.   LogLine('New Class instance Created: ' + CreatedClass.ToString);
  4. end;
As you can see the LogClassCreation does only need the ToString function and nothing else, therefore it only requires a promise that the class will have this method, and this promise is made by having the type of the parameter being the Interface that creates this promise.

In this respect Interfaces are the same across most languages, and it is also like in golang.

Now comes the complicated part. Pascal has two types of interfaces, CORBA and COM. CORBA interfaces are the "raw" interfaces, which are basically just the promise I described above. To use them simply add a {$Interfaces CORBA} to your unit and you have the simple, raw, go-like interfaces.

The other (default) form of interfaces are COM interfaces, which basically add reference counting to it. If a class implements a COM interface it must also implement the _AddRef, _Release and and QueryInterace function. There you would need to implement your own reference counter. But, to make it simple, FPC provides the TInterfacedObject Class, which already implements those functions, so if you inherit from it, you don't have to care about it.

The "problem" with COM interfaces is, as they are reference counted, but normal pascal classes are manually managed, you cannot combine those two paradigms as easiely. So if you have a COM interface, it's best to only touch it via the interface. So for example, while this code is completely fine with CORBA interfaces:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$Interfaces CORBA}
  5.  
  6. type
  7.   IPrintable = interface
  8.   function ToString: String;
  9.   end;
  10.  
  11.   TTest = class(TInterfacedObject, IPrintable)
  12.   public
  13.     function ToString: ansistring; override;
  14.   end;
  15.  
  16. procedure LogClassCreation(CreatedClass: IPrintable);
  17. begin
  18.   WriteLn('New Class instance Created: ' + CreatedClass.ToString);
  19. end;
  20.  
  21. function TTest.ToString: ansistring;
  22. begin
  23.   Result := 'TTest';
  24. end;
  25.  
  26. var
  27.   t: TTest;
  28.  
  29. begin
  30.   t := TTest.Create;
  31.   try
  32.     LogClassCreation(t);
  33.   finally
  34.     t.Free;
  35.   end;
  36. end.
  37.  
When interfaces change the [$Interfaces CORBA} to COM (or delete it as COM is the default), it will cause a double free, because when entering "LogClassCreation", the reference counter is increased to 1, and when leaving it dropps to 0 and is therefore freed, even though the main code still has the reference "t" but because this is not a COM interface reference, it does not count into the reference counter.
Therefore when you use something as a COM interface once, it's best to use it always as a COM interface.

So while COM and CORBA in principle serve the same purpose, to give promises about functionality, generally CORBA interfaces are much simpler and are more like your Go interfaces, while COM provide powerful reference counting, but on the other hand are not as easiely compatible with "normal" pascal code.
This also means that if you want to use many small interfaces (for encapsulation), COM is usually not that useful for that, because you must always be handling at least one COM interface, so if you only have a lot small ones, you need to do a lot of conversions (because remember, you always must touch the object as an interface), while with CORBA, you handle your object like a normal Pascal object for the most parts, and only use it as the interface when needed.

For me the rule of thumb is: I always use CORBA when I want to use interfaces as the classical "promise", and COM only if I need a reference counted pointer (smartpointer) for my class, and in those cases my COM interface is basically just a complete copy of the "public" parts of the class I am writing, and I just use this rather than the class itself.

An example where the latter might come in useful is for example the GMP Unit:
Code: Pascal  [Select][+][-]
  1. var a, b: MPInteger;
  2. begin
  3.   a := 42;
  4.   b := 3;
  5.   a := a * b + b;
  6. end;
Here MPInteger is a COM interface, and therefore, even though a and b are classes, because they are reference counted, there is no need of writing ".Free" anywhere and you can use operators. But you need to always use a and b as MPInteger and never as the underlying class, because otherwise you would run into memory management issues
« Last Edit: October 02, 2022, 11:10:40 am by Warfley »

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 782
Re: Good explaination of how interfaces work.
« Reply #10 on: October 02, 2022, 11:25:47 am »
Yeah, it's more simple and more intuitive explanation of multiple polymorphism. Because "promises to implement certain methods and properties" = "inherits from" and "I don't care, what kind of type something really is - it just should implement some methods and properties" = "polymorphism".
29.12.2021 - migration to DynamicData 4.1 is completed - complete overhaul of data access driver.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 13 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5569
Re: Good explaination of how interfaces work.
« Reply #11 on: October 02, 2022, 11:29:13 am »
I believe I see what you're getting at and hopefully it will help OP.

One question: would it be valid to change the order to read

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$Interfaces CORBA}
  5.  
  6. type
  7.   IPrintable = interface
  8.   function ToString: String;
  9.   end;
  10.  
  11. procedure LogClassCreation(CreatedClass: IPrintable);
  12. begin
  13.   WriteLn('New Class instance Created: ' + CreatedClass.ToString);
  14. end;
  15.  
  16. type
  17.   TTest = class(TInterfacedObject, IPrintable)
  18.   public
  19.     function ToString: ansistring; override;
  20.   end;
  21.  
  22. function TTest.ToString: ansistring;
  23. begin
  24.   Result := 'TTest';
  25. end;
  26.  
  27. var
  28.   t: TTest;
  29.  
  30. begin
  31.   t := TTest.Create;
  32.   try
  33.     LogClassCreation(t);
  34.   finally
  35.     t.Free;
  36.   end;
  37. end.
  38.  

which emphasises that LogClassCreation() takes an ancestor (used loosely) of TTest which is so far undefined?

Another point for OP is that somebody referred to a GUID being /allocated/ (or similar), in general there isn't a central authority and it will be created locally in a way that (hopefully) won't clash with anybody else's usage.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Thaddy

  • Hero Member
  • *****
  • Posts: 12196
Re: Good explaination of how interfaces work.
« Reply #12 on: October 02, 2022, 11:35:48 am »
Never put programmers on the wrong foot by promoting CORBA. It has no use other than confuse.
Manuals, manuals, manuals first.
You have incompetence and sheer incompetence.

Warfley

  • Hero Member
  • *****
  • Posts: 941
Re: Good explaination of how interfaces work.
« Reply #13 on: October 02, 2022, 11:49:20 am »
Never put programmers on the wrong foot by promoting CORBA. It has no use other than confuse.
I don't think CORBA is very confusing, it is exactly what you think of an interface when you come from any other language. It's just a set of functions and properties your class must provide. The confusing thing is COM interfaces, which have a completely different memory management model from traditional lazarus, require the inheritance from TInterfacedObject and are incompatible with normal pascal code.

I think if one is searching for interfaces, as they know them from Java, or in this case Go, to just tell the code "Hey the object is going to have the following functions", than CORBA is the way to go. If you are searching for a referencecounted type that is incompatible with manual memory management and requires custom implementation of the reference counting functionality, than you are good to go with COM. Personally I find myself much more often in the former situation than in the latter.

Arioch

  • Sr. Member
  • ****
  • Posts: 414
Re: Good explaination of how interfaces work.
« Reply #14 on: October 02, 2022, 05:33:12 pm »
First of all, forgett about multi inheritance, this most cerntainly only complicates it

Interestingly, that if we talk about COM interfaces - then there should be no inheritance at all.

Yes, Delphi/FPC allow it. But if to read the founding concepts then there is "Inheritance was mistake. Inheritance was poison no one recognized in time. Inheritance is wrong and we removed it from COM. For complex behaviour you need go with delegation not inheritance".  Multiple or singlular - any inheritance is considered harmful.

And that is the reason why COM interfaces must all have the same first three methods. Because there is no "parent interface" they could inherit from. This copy-paste is the price COM designers are paying for the purity of their concept.

And OOP interfaces, as C++ prgrammers say, are merely classes with only abstract virtual methods, that do not deserve a special keyword :-)

 

TinyPortal © 2005-2018