I think it is a bit light on the module/unit system.
I think it is a bit light on the module/unit system.
And on string types (compared to C) and why they are faster to evaluate and have some distinct advantages over just only zero terminated strings.. I noticed that when answering a different question and I am now reading it more thoroughly.
7.1. Local (nested) routines
....
....
Another version, where we let the local routine Square to access I directly:]
found small typo atQuote7.1. Local (nested) routines
....
....
Another version, where we let the local routine Square to access I directly:]should be
... for I := 0 to N do Result := Result + Square(I);
... for I := 0 to N do Result := Result + Square;
QuoteI think it is a bit light on the module/unit system.
What would you like to add specifically?:)
says that "is" operator can be used only on com interfaces!huh ?
Is the documentation wrong?
An expression containing the is operator results in a boolean type. The is operator can only be used with a class reference or a class instance.and
The as and is operators also work on COM interfaces.:D
says that "is" operator can be used only on com interfaces!huh ?
Is the documentation wrong?
No, you are simply not reading _all_ :-)QuoteAn expression containing the is operator results in a boolean type. The is operator can only be used with a class reference or a class instance.andQuoteThe as and is operators also work on COM interfaces.:D
Hello, Molly,Ah ok. Your question was specifically with regards to corba interfaces. I interpreted that wrongly.
But in the example the is operator is used for CORBA interface. Isn't that in contrast to the documentation?
Also note the final sentece in this Reference Guide topic: "Although the interfaces must be COM interfaces, ..."Selective reading always deliver nice results :-)
...the typecast back to a class will only work if the interface comes from an Object Pascal class.Which explains, i guess, why it works for corba interfaces as well ?
QuoteAlso note the final sentece in this Reference Guide topic: "Although the interfaces must be COM interfaces, ..."Selective reading always deliver nice results :-)
Please also read directly after that:Quote...the typecast back to a class will only work if the interface comes from an Object Pascal class.Which explains, i guess, why it works for corba interfaces as well ?
See also this (http://www.freepascal.org/docs-html/ref/refse46.html)There is nothing about "is" operator and corba.
Numerous examples show that we simply add strings, and pass them around to/from functions.
QuoteThe as and is operators also work on COM interfaces.:D
Sorry, I don't think that I read it selectively, I read it thoroughly several times.Oops, sorry. that might have come across as an accusation (which it was not meant to be).
You really think that it says to the reader that CORBA interfaces can use "is" operator, as well as COM interfaces?No, it does not say that nor did i ever mentioned that it does.
There is nothing about "is" operator and corba.That wasn't my point. Point was that it explains that support for corba interfaces is present.
I am still confused...1. The official documentation regarding the class operator is does not specifically mention corba interfaces
But it is a bad idea to use themWell, if i remember correctly i did not mention explicitly that you should use it :)
They are too slow
I also would remove the apologetic "reasonable", and refer to Pascal's "declare before usage" principle. ( I assume it is somewhere mentioned near the beginning).
Qualified identifier usage, and, related, type aliases. (type xx = unity.xx)
FPC Reference Guide (topic about class operators) says that "is" operator can be used only on com interfaces!
Or to put it into other words: i thought the record/advanced record chapter was a bit small and a bit tucked away.
It is a trap.
You make all your functions for string, and then you get a pchar and cannot use it with any of them
Better use only pchar for functions
QuoteThe as and is operators also work on COM interfaces.
But it is a bad idea to use them
They are too slow
Sure, it's good to avoid run-time checking with "is", and casting with "as". Not only faster, but also the code is safer.
QuoteThere is nothing about "is" operator and corba.That wasn't my point. Point was that it explains that support for corba interfaces is present.
In case you feel 'betrayed' because the official documentation regarding the is operator does not state specifically that it also works with corba, then please feel free to file a bugreport on mantis ?
Quote from: ZoranFPC Reference Guide (topic about class operators) says that "is" operator can be used only on com interfaces!
There were some things that didn't work with CORBA interfaces in the past. With FPC 3.0.0 things just work, and I would focus on that:) The "is" and "as" operators work as expected on both COM and CORBA interfaces now. Since they are consistent with classes and wotk for both interface types now, I would advice just using them.
Note that for COM, you can also use the "Supports" function, but for CORBA the only way to check is to use "is" (as far as I know).
It seems that this part of the FPC documentation was simply not updated.
I definitely do not want to use PChar in all my functions, it would mean throwing away all the comfort that AnsiString brings.
And you can, with some safety cautions (UniqueString etc.) convert AnsiString to PChar. That's one of the advantages of AnsiString.
You should not reject a useful language construct because "it has a performance cost", in my opinion. A lot of things have a performance cost.
BeniBela : You do realize that converting constant strings to PChars include slight penalty in FPC 3.x series?
What I just realized last week, when you use strings the entire function gets wrapped in a try .. finally block, at least on linux amd64. That is really bad.
The real issue are slices. E.g. you have a 1000 character string s and want to do something with the middle, characters s[400] to s[600]. With a pchar, you can just point in the middle and use a smaller length. With a string, everything in that range needs to be copied.
Reading documentation is an art. You can turn that behavior off... If you really don't want it.
{$IMPLICITEXCEPTIONS OFF}
Huh? Why? Of course not! Example please....
That is hard to findIt is in the programmer's manual? So it is easy to find....
Huh? Why? Of course not! Example please....
https://github.com/benibela/bbutils/blob/master/bbutils.pas#L2566-L2588I' ll look into it..
Wow, thank you everyone for the comments! Here's a large answer:)Well, thank you very much for the write-up. The least a person could do is giving it a read :hint hint: :D
Fair enough, especially since you have a particular reader in mind.Quote from: mollyOr to put it into other words: i thought the record/advanced record chapter was a bit small and a bit tucked away.
That is deliberate indeed. I wanted to focus on our main concept, which is "class".
....
Okay, the thing is that I believe that it actually didn't work in the past, so I was confused when I saw the example and tried to compile it and it just worked.In understand and i apologize for the confusion i might have caused.
Thank you very much Zoran. It seems it is already addressed as well.In case you feel 'betrayed' because the official documentation regarding the is operator does not state specifically that it also works with corba, then please feel free to file a bugreport on mantis ?Okay, bug report 30308. (http://bugs.freepascal.org/view.php?id=30308)
Yes, that is the advantage of having ansistring, you can call the functions who takes pchars.
But not the other way around, thus it is better, if all your functions take pchars.
What I just realized last week, when you use strings the entire function gets wrapped in a try .. finally block, at least on linux amd64. That is really bad.
The real issue are slices. E.g. you have a 1000 character string s and want to do something with the middle, characters s[400] to s[600]. With a pchar, you can just point in the middle and use a smaller length. With a string, everything in that range needs to be copied.
One minor correction. "As in all object-oriented languages", should be "most" instead of "all" in section 4.5
I still don't understand why all examples are written in console. Ask a beginner what console/DOS/cmd/command is and they look at you like a crazy person. My point of view should using GUI demo'sI do see a lot of beginners (I mean real beginners to programming) using the command line. Usually they come in contact with Pascal through lessons and are instructed to use fp.exe or even Dev-Pascal (or similar).
The rest of this article talks about the Object Pascal language, so don’t expect to see anything more fancy than the command-line stuff. If you want to see something cool, just create a new GUI project in Lazarus (Project → New Project → Application). Voila — a working GUI application, cross-platform, with native look everywhere, using a comfortable visual component library.
This is directed at programmers (who know a bit of some programming language, though not necessarily Pascal). Which is really an excuse to not explain in detail some basic stuff ("what is a variable", "what is a class"). I tried to explain more the "advanced" stuff, and illustrate everything with examples.
I like the idea to have documentation online for beginners.I prefer offline documentation I can read at a location where I might not have internet access. eg: 30,000 feet on a long haul flight, night time reading while on vacation, on a train to work or meetings etc. And its incredible [in this day and age] how often I am at a location where there is no internet access.
I'm not a beginner and I'm still confused by some paragraphs.From what I've seen, reading that text should be taken with a pinch of salt - meaning in is the personal opinion of the author. Your and my oppinions might be different. eg: I see absolutely nothing wrong with using TList, TObjectList and packed records. In fact I have code where the usage of them are vital.
I still don't understand why all examples are written in console. ...snip... My point of view should using GUI demo'sIt is very simple. Is it a tutorial about the Object Pascal language or a GUI toolkit? It's the former. Introducing a GUI toolkit into the sample code means you are now speaking only to say Lazarus LCL developers. What about FPC developers using Web Services, Unix daemons, MSEgui, fpGUI etc? Console demos don't introduce an extra [unnecessary] dependency or complexity. The information is about Free Pascal's programming language, Object Pascal, and the RTL and FCL. Console demos make perfect sense and should not be changed. This is also why FPC includes only console demos.
Wow, thank you everyone for the comments! Here's a large answer:)Quote from: marcovI also would remove the apologetic "reasonable", and refer to Pascal's "declare before usage" principle. ( I assume it is somewhere mentioned near the beginning).
I reworded and shortened this part a bit. Thanks:)
It was apologetic, because indeed other languages do not have this limitation --- e.g. in Java you also usually need to declare stuff before using it, and yet two classes, in two separate files, can freely use each other.
Thaddy, you know, i used pascal strings a lot in past but when needed to write code compatible with C code, turned to PChar uses. And using of PChar is much simpler for me, i can control all things, i clearly know what happens...
Yup ;) But that still does not allow #0 in the middle. These are simply overflow protections. A standard C string library (well, array of byte ultimately) breaks on its terminator which happens to be zero or $0 or 0x0 or naught. You know that. Hence the max count... doesn't work ;)Thaddy, you know, i used pascal strings a lot in past but when needed to write code compatible with C code, turned to PChar uses. And using of PChar is much simpler for me, i can control all things, i clearly know what happens...
(btw, Proper modern C code works with a pchar and a max count (the -n- functions))
But that still does not allow #0 in the middle.
From what I've seen, reading that text should be taken with a pinch of salt - meaning in is the personal opinion of the author. Your and my oppinions might be different. eg: I see absolutely nothing wrong with using TList, TObjectList and packed records. In fact I have code where the usage of them are vital.
Indeed, in some places I felt an advice "what to use, if you have these two alternatives" was necessary.
For records -- I don't discourage them. I just suggest that "class" is the default feature-rich structural type which one usually uses in Object Pascal. I think this is generally accepted among Object Pascal programmers. Records definitely have their use...There are indeed cases where Records are the best or only choice. eg: reading a binary file (eg: an INF help file), it is hugely beneficial to use a record structure to read such binary data. I would not dream of using a class in such a situation.
The other place where I definitely expressed my opinion are interfaces -- I explicitly encourage CORBA interfaces over COM in the article. They are closer to C# and Java interfaces. And they do not bring "automatic reference counting" (which I feel should be an orthogonal feature of the language, not entangled with interfaces).
This is a very good introduction.
Could you add (perhaps in the "About" section at the end) a notice about the version of the document and the date of last change? This would make life easier for readers, by providing a hint if it is worthwhile to download a new version.
This is a very good introduction.There is a "Last updated" date at the very bottom of the HTML version, see http://michalis.ii.uni.wroc.pl/~michalis/modern_pascal_introduction/modern_pascal_introduction.html . And the exact history of the document may be seen in the GitHub repository on https://github.com/michaliskambi/modern-pascal-introduction . The commits on https://github.com/michaliskambi/modern-pascal-introduction/commits/master document precisely what and when changed:) I update the HTML/PDF output after every commit.
Could you add (perhaps in the "About" section at the end) a notice about the version of the document and the date of last change? This would make life easier for readers, by providing a hint if it is worthwhile to download a new version.
The COM part is still not correct as I explained in my email to you, because it reflects the only way you should not ever never use COM.
I will do a follow up (as per email) this weekend. For starters: there are no memory leaks....
COM should be used through interface instances, not class instances as in your book. And you should respect the reference counting. TComponent is a really bad example...
"GOOD" and "UGLY" interfaces is really not serious in a technical writing. You're not the guy who decides that. Some people have to work with COM as a constraint, your opinion does not matter, they have to do it. dot.
You could put a paragraph about class var, class properties, class constructor and class destructor.
If you *want* the reference-counting of COM interfaces, then COM interfaces are a good deal. I'm open to improvements, my example and wording could probably be improved.
Perhaps it is time to add a third kind of interfaces to FPC
Reference counted like COM, but otherwise like CORBA, without any of the COM overhead
Perhaps it is better to study what there is first :-)
The COM overhead part is in its implementation (iow TInterfacedObject and/or descendants) not the interface itself.
Dont ever mix up class instantiation with interface instantiation. It is still the same mistake I already reported. Is that SO difficult to understand?
You still have no clue about interfaces. It's a piece of shit that part. Do I make myself clear.
Dont ever mix up class instantiation with interface instantiation. It is still the same mistake I already reported. Is that SO difficult to understand?
It really is time to get rough and ... rude..
There is quite some overhead, because the value of the interface instance is not the same value as self of the class instance.
So on every usage it needs to calculate self from the interface variable. The same calculation again and again.
Or the inverse calculation when the interface is created.
In the working case I presented above this is nonsense as well. The overhead is in creation/release and that is all. You could have known that, you are not a nobody. (Although you are trolling "a bit" lately IMO :) )
0000000000400208 488b00 mov (%rax),%rax
000000000040020B ff5008 callq *0x8(%rax)
WRPR_$SYSTEM_$$_TINTERFACEDOBJECT_$_IUNKNOWN_$_1_$_SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT
0000000000422C50 4883ef10 sub $0x10,%rdi
0000000000422C54 e90706ffff jmpq 0x413260 <SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT>
00000000004001F0 e88b300100 callq 0x413280 <SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT>
procedure InitInterfacePointers(objclass: tclass;instance : pointer);
var
ovmt: PVmt;
i: longint;
intftable: pinterfacetable;
Res: pinterfaceentry;
begin
ovmt := PVmt(objclass);
while assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
begin
intftable:=ovmt^.vIntfTable;
if assigned(intftable) then
begin
i:=intftable^.EntryCount;
Res:=@intftable^.Entries[0];
while i>0 do begin
if Res^.IType = etStandard then
ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
pointer(Res^.VTable);
inc(Res);
dec(i);
end;
end;
ovmt:=ovmt^.vParent;
end;
end;
In the working case I presented above this is nonsense as well. The overhead is in creation/release and that is all. You could have known that, you are not a nobody. (Although you are trolling "a bit" lately IMO :) )
Perhaps it changes with smartpointers
Look at how it calls a COM function, e.g. _Addref:Code: [Select]0000000000400208 488b00 mov (%rax),%rax
000000000040020B ff5008 callq *0x8(%rax)
WRPR_$SYSTEM_$$_TINTERFACEDOBJECT_$_IUNKNOWN_$_1_$_SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT
0000000000422C50 4883ef10 sub $0x10,%rdi
0000000000422C54 e90706ffff jmpq 0x413260 <SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT>
That is four times the amount of calling an ordinary method of a class:Code: [Select]00000000004001F0 e88b300100 callq 0x413280 <SYSTEM$_$TINTERFACEDOBJECT_$__$$__ADDREF$$LONGINT>
And the creation overhead is enormous, too, as it calls:Code: [Select]procedure InitInterfacePointers(objclass: tclass;instance : pointer);
var
ovmt: PVmt;
i: longint;
intftable: pinterfacetable;
Res: pinterfaceentry;
begin
ovmt := PVmt(objclass);
while assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
begin
intftable:=ovmt^.vIntfTable;
if assigned(intftable) then
begin
i:=intftable^.EntryCount;
Res:=@intftable^.Entries[0];
while i>0 do begin
if Res^.IType = etStandard then
ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
pointer(Res^.VTable);
inc(Res);
dec(i);
end;
end;
ovmt:=ovmt^.vParent;
end;
end;
That's in any language. Nothing to do with Object Pascal. You know that too ;)
Look at calls through variants that's even worse.
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 only see one call and then a jump to right method.
Nowadays CPU's are quite fast so there shouldn't have noticeable slowdowns on (massive) usage of interfaces.
There is quite some overhead, because the value of the interface instance is not the same value as self of the class instance.
Zoran, He - and by proxy, you too - has no clue about both types of interfaces.
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.
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?
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.
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.
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;
ad 2. does not need 1. but may implement it anyway, often by accidentWhat 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?
or lack of knowledge.
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;
As far as I am concerned that is implementation detail, Maciej. What I wrote is perfectly in line with the theory.
That is not true. For non-reference-counted IInterface implementation we have dedicated class: TSingletonImplementation in "Generics.Defaults" module.
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.
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.
Reference counted vs non-reference counted interfaces
The information that you can add reference-counting to CORBA interfaces is interesting, thank you. I will change the article to mention it, to make it clear that all interfaces can be ref-counted, just CORBA is by default not ref-counted.
The information that you can add reference-counting to CORBA interfaces is interesting, thank you. I will change the article to mention it, to make it clear that all interfaces can be ref-counted, just CORBA is by default not ref-counted.
(actually real Corba interfaces are, just not via unknown, and typically managed manually. The name was always bad, please mention that :-))
Stress that non reference counted interfaces are more "bare" and deemphasize the link to corba and java. Note that iunknown doesn't just do refcounting though, it also plays a part in identity (queryinterface (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521(v=vs.85).aspx)) that allows to get other interfaces supported by the object from the object. (e.g. to see if you can "upcast" an interface to a newer version)