Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2005-04

"is"

25 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Unknown author

Ok, I got back too late yesterday and now I was examining my patch. And I was surprised when I noticed that I didn't remembered my patch as it was out of my head.

My patch never changed any (class is TClass) handling, all inside is your code. I only changed after
else (it's not relaxed and won't be as it was said n mail about relaxed mode), and I all along thought that I forgot to check is_related. How it could do too much, did you even inspect the code???

I should probably ask now: "Can I now really get answer what would the problem be?? Interface has no code and thus "is" should be flexible, class has code and it should not be flexible." but I won't, it's getting tiresome, and as always I won't get answer.

class "is" (some not related class) - bad
interface "is" (some not related interface) - good, that is how it is supposed to work, and you can't make MI interfaces without this option.

I'm on about 90% of working MI interfaces and after that is inclass implementation and foreach (inclasses are much better solution than completely missed "implementing interfaces by delegation" or "naming resolution clauses". Whoever needs those two, well it can implement them, I wont because they are stupid and delphi compatible is not on my needed list"). Don't worry, I won't bother you to include MI, inclasses or foreach (in fact I don't even think about it), I suspect it would just lead to another tiresome thread. I'll just notify you, where you can download the patch and documentation, and what you do with it is your decision (somehow history on this mailing list made me think that I would be better off even not knowing your decision). As I said I only want to contribute things incommon and not force anybody.

I can't fix the problem if I don't know what the problem is. You can either:
- say where the problem lies (example)
- correct it as you wan't (I can't, I don't know where problem is)
- implement it on your own
- use my patch
- send my patch in trash and live without (I won't)

Personaly, I stopped carring (its been a week or two now, and I still haven't got the answer even where the problem lies)

ml

---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/)

Reply by email

Florian Klaempfl
to Unknown author
Personaly, I stopped carring (its been a week or two now, and I still haven't got the answer even where the problem lies)

Well, we try currently prepare 2.0 so the focus is currently on bug fixing so nobody of the developers had time to investigate the patch more deeply yet so 1-2 weeks of delay aren't that big :)

Reply by email

Unknown author
to Florian Klaempfl

Quoting Florian Klaempfl :

Show quoted text 9 lines
wrote: > Personaly, I stopped carring (its been a week or two now, and I still haven't > got the answer even where the problem lies) Well, we try currently prepare 2.0 so the focus is currently on bug fixing so nobody of the developers had time to investigate the patch more deeply yet so 1-2 weeks of delay aren't that big :)

2.0 is being mentioned first at 25 september 2003 (<joke>wow, that's a long "currently", and a lot of 1-2 weeks</joke>)? And my best guess is that interfaces are not part of the 2.0 plan (even bug reports and fixes I made were completely ignored, just like interfaces aren't part of the 2.0 goal).

Then just answer this:

Would it be better if I develop things off your mailing list and just notify about things being done 100% (and available for testing, and if it suits you...). There are two ways: on my page or on freshmeat. If interfaces being able to work aren't 2.0 plan then I just waste your time (and even more of mine just sitting and waiting). It is as I said, my project would contain about 2-3 mio lines taking the current state of pascal, and I need to remake some things for my self (to lower things down to 500000-750000 I have to make changes to compiler), but if they can be of any use to somebody, well it's free as in beer.

Why maybe affirmative answer would be better?
It would be better for me because answers wouldn't take forever. And it would be better for you because I wouldn't bug you. And then if you need something you take, it will be under the LGPL license.

Features being developed now are:
MI interfaces 90% (MI=multiple inheritance)
Inclasses 15% (embedded classes)
foreach 0% (well, we know you hate it)
box-type 0% (something like variant, but simpler, better and less memory consuming)

and some other things which are mostly done, but my best guess is that will be pascal-off or too- heretic-like and used by me only.

ml

_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/)

Reply by email

Florian Klaempfl
to Unknown author
Show quoted text 18 lines
Quoting Florian Klaempfl : > wrote: > >>Personaly, I stopped carring (its been a week or two now, and I still > >haven't > >>got the answer even where the problem lies) > >Well, we try currently prepare 2.0 so the focus is currently on bug >fixing so nobody of the developers had time to investigate the patch >more deeply yet so 1-2 weeks of delay aren't that big :) > 2.0 is being mentioned first at 25 september 2003

And?

(<joke>wow, that's a long "currently", and a lot of 1-2 weeks</joke>)? And my best guess is that interfaces are not part of the 2.0 plan (even bug reports and fixes I made were completely ignored, just like interfaces aren't part of the 2.0 goal).

Interfaces are part of 2.0 but mainly to be dephi compatible.

Show quoted text 10 lines
Why maybe affirmative answer would be better? It would be better for me because answers wouldn't take forever. And it would be better for you because I wouldn't bug you. And then if you need something you take, it will be under the LGPL license. Features being developed now are: MI interfaces 90% (MI=multiple inheritance) Inclasses 15% (embedded classes) foreach 0% (well, we know you hate it)

It's a useless statement if used for arrays, enumerations etc. It blows up the language for no gain. I really wonder what people would say about a foreach which iterates through arrays in random order. I guess 90 per cent of the programs break though it would be completely legal :)

It makes some use for containers like maps however those aren't native types in pascal.

box-type 0% (something like variant, but simpler, better and less memory

consuming)

and some other things which are mostly done, but my best guess is that will be

pascal-off or too-

heretic-like and used by me only.

History has shown that using incompatible solutions isn't that good. Simply because people prefer to compile their sources with different compilers.

Reply by email

Thomas Schatzl
to Florian Klaempfl

Hello,

everything below is imho as usual... ;)

Show quoted text 7 lines
>(<joke>wow, that's a long "currently", and a lot >of 1-2 weeks</joke>)? And my best guess is that interfaces are >not part of the 2.0 plan (even bug reports and fixes I made were >completely ignored, just like interfaces aren't part of the >2.0 goal). Interfaces are part of 2.0 but mainly to be dephi compatible.

Does that mean that the incompatibilites/bugs for "as", "is", reference counting (assuming that the current behaviour is as ml says), see bug list, will be fixed for 2.0 or not?

Show quoted text 9 lines
>Features being developed now are: >MI interfaces 90% (MI=multiple inheritance) >Inclasses 15% (embedded classes) >foreach 0% (well, we know you hate it) It's a useless statement if used for arrays, enumerations etc. It blows up the language for no gain. I really wonder what people would say about a foreach which iterates through arrays in random order. I guess 90 per cent of the programs break though it would be completely legal :)

I don't think it'd be a major shortcoming to just define the iteration order for special types (arrays).
Similar to that the high() operator for sets (discussed some time ago). Or enumerations that are implicitely ordered.

E.g.
type
	shapes = (circle, box);

and circle < box evaluating to true, which doesn't really make sense either.

And D9 does have them.

It makes some use for containers like maps however those aren't native types in pascal.

Syntactic sugar, and could be available for classes which implement a certain interface as well (as in other languages). This implementation defines a "natural" guaranteed iteration order, which is documented. I would not see a problem with that.

An array is more or less an ordered set of elements (elements having a strict natural ordering imposed by the indices, or, position in the array), or another example, in a class called TLinkedList I'd expect to get an iteration order according to the element order, and if I used it as a Collection, I'd expect no natural ordering (the name in this case serving as documentation).
Similar to your example where you wouldn't expect any ordering in a Map if you iterated over it since it simply does not have a natural ordering.

Show quoted text 6 lines
>and some other things which are mostly done, but my best guess is that will be pascal-off or too-heretic-like and used by me only. History has shown that using incompatible solutions isn't that good. Simply because people prefer to compile their sources with different compilers.

<provocative>
OBJFPC and FPC mode are already incompatible to e.g. DELPHI and TP mode or not? These things are not breaking backwards compatibility within that particular mode or not?

=)
</provocative>

Regards,
Thomas

Reply by email

Unknown author
to Florian Klaempfl: And? Interfaces are part of 2.0 but mainly to be dephi compatible. It's a useless…

Quoting Florian Klaempfl :

Show quoted text 31 lines
wrote: > Quoting Florian Klaempfl : > > >> wrote: >> >>>Personaly, I stopped carring (its been a week or two now, and I still >> >>haven't >> >>>got the answer even where the problem lies) >> >>Well, we try currently prepare 2.0 so the focus is currently on bug >>fixing so nobody of the developers had time to investigate the patch >>more deeply yet so 1-2 weeks of delay aren't that big :) >> > > > 2.0 is being mentioned first at 25 september 2003 And? > (<joke>wow, that's a long "currently", and a lot > of 1-2 weeks</joke>)? And my best guess is that interfaces are not part of the 2.0 plan (even bug > reports and fixes I made were completely ignored, just like interfaces aren't part of the 2.0 goal). Interfaces are part of 2.0 but mainly to be dephi compatible.

You mean that 20% of functionality of delphi interfaces that you currently support?

Show quoted text 19 lines
> > Why maybe affirmative answer would be better? > It would be better for me because answers wouldn't take forever. And it would be better for you > because I wouldn't bug you. And then if you need something you take, it will be under the LGPL > license. > > Features being developed now are: > MI interfaces 90% (MI=multiple inheritance) > Inclasses 15% (embedded classes) > foreach 0% (well, we know you hate it) It's a useless statement if used for arrays, enumerations etc. It blows up the language for no gain. I really wonder what people would say about a foreach which iterates through arrays in random order. I guess 90 per cent of the programs break though it would be completely legal :)

Why did I know that even though I specified you hate it (and with this I was meaning that it will never get to fpc tree), that this will be the only thing mentioned in answer

It makes some use for containers like maps however those aren't native types in pascal.

Yeah, just like MI interfaces aren't doable (I think that you said "impossible"), it was about 40-50 lines adding and about 10 lines of change (currently I'm still testing to be 100%, but yes they are done). And inclasses are now at 30%.

Containers? Hello, that's why I'm implementing box type. Everything is doable, you know the array or set, classes in other languages just specify interface IEnumerable, and they support for each. As I said I don't care if any of my changes gets into fpc tree. If you like it, you can have it, as free as in beer, that's why I asked if I should remove my work to other place and just notify you when feature is 100% and available for your testing whether you like it or not.

Show quoted text 11 lines
> box-type 0% (something like variant, but simpler, better and less memory consuming) > > and some other things which are mostly done, but my best guess is that will be pascal-off or too- > heretic-like and used by me only. History has shown that using incompatible solutions isn't that good. Simply because people prefer to compile their sources with different compilers.

So delphi supports operators? and few other objfpc things?

<LOL>bwaaaahhhhh</LOL>. but to get serious

Somehow I sound like a bad guy here, that's trying to force his opinion.

Isn't the main reason I try to help here (and I specified it now for at 5 times) that I don't wanna break anything to you with my patches. Patches will be done. Patches will be downloadable (if they don't get in fpc tree). I would be more or less 90% done already if I wouldn't go trough this yapping and waiting.

btw. Don't you think that I would do things under my name if I would wish any kind of gratitude or fame? Nope, I would just like to contribute (as thanks for your work), but not only to you but to whole community. I always did, and I always will.

ml

Show quoted text 5 lines
_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/)

Reply by email

Florian Klaempfl
to Unknown author
Show quoted text 5 lines
>Interfaces are part of 2.0 but mainly to be dephi compatible. > You mean that 20% of functionality of delphi interfaces that you currently support?

Well, those 20% cover 80% of interface usage. The most important where interfaces are used is COM importing and that works usually ;)

So delphi supports operators? and few other objfpc things?

No, but those are ancient. The problem is with extensions that they must be maintained as every feature because they get broken from time to time. This is simply experience or just follow up the online testsuite results. Though everybody is careful with its patches, test results get worse if nothing is done. So we're careful with adding new features.

Reply by email

Michael Van Canneyt
to Unknown author: Quoting Florian Klaempfl : You mean that 20% of functionality of delphi interfaces that…
Show quoted text 7 lines
Containers? Hello, that's why I'm implementing box type. Everything is doable, you know the array or set, classes in other languages just specify interface IEnumerable, and they support for each. As I said I don't care if any of my changes gets into fpc tree. If you like it, you can have it, as free as in beer, that's why I asked if I should remove my work to other place and just notify you when feature is 100% and available for your testing whether you like it or not.

I think it is best that you finish your work, and then provide a complete patch. But please split the patches in separate chunks, so we can clearly distinguish bug-fixes from features.

Show quoted text 19 lines
>> box-type 0% (something like variant, but simpler, better and less memory > consuming) >> >> and some other things which are mostly done, but my best guess is that will > be > pascal-off or too- >> heretic-like and used by me only. > > History has shown that using incompatible solutions isn't that good. Simply > because people prefer to compile their sources with different compilers. > So delphi supports operators? and few other objfpc things? <LOL>bwaaaahhhhh</LOL>. but to get serious Somehow I sound like a bad guy here, that's trying to force his opinion.

No, but it seems to me that you fail to provide good arguments to make us accept the general usefullness of your patches.

Usually, when the core developers are not convinced of the usefullness of a feature, it is not implemented or included.

I have not yet seen any argument from your side to convince me that your patches are a useful contribution to the pascal language. That your patches reduce your code base by a factor 4, seems to me an argument that maybe your design is flawed and not that pascal is flawed. Pascal works for me as it is. It works even very well, and I haven't seen a situation where it failed me or I would need any of the features you suggest. So why would it not be so for you ?

Take care: I am not suggesting your currently design is actually flawed; But you have not convinced me that your patches are an improvement of the pascal language.

For example;
MI for interfaces for me is strange (to say the least) because interfaces were introduced to avoid the mess of MI in the first place. So why on earth would you want to introduce it ??

Show quoted text 9 lines
Isn't the main reason I try to help here (and I specified it now for at 5 times) that I don't wanna break anything to you with my patches. Patches will be done. Patches will be downloadable (if they don't get in fpc tree). I would be more or less 90% done already if I wouldn't go trough this yapping and waiting. btw. Don't you think that I would do things under my name if I would wish any kind of gratitude or fame? Nope, I would just like to contribute (as thanks for your work), but not only to you but to whole community. I always did, and I always will.

Any contribution is appreciated, but we must be convinced of it's usefullness if it is a feature. If you (or anyone else) fail to make us see that, the patch won't get included. This is a simple fact.

You should not take this personal or whatever, but that is how things work for FPC.

As for the 'is' patch: It is obviously not a simple issue or it would already have been applied. Provide a complete patch, we'll study it, but we cannot guarantee that this will be done fast. The more involved a patch is, the longer it takes to review it, and to estimate possible consequences...

Michael.

Reply by email

Thomas Schatzl
to Thomas Schatzl: everything below is imho as usual... ;) Does that mean that the incompatibilites/bugs for…

Hello,

I think I have to make some things more clear why I am in favor of that "foreach":

Show quoted text 7 lines
>> Features being developed now are: >> MI interfaces 90% (MI=multiple inheritance) >> Inclasses 15% (embedded classes) >> foreach 0% (well, we know you hate it) > > It's a useless statement if used for arrays, enumerations etc. It > blows up the language for no gain.

You are right, for arrays, enumerations etc. there is little to no gain. But I see the application of foreach on these types as added bonus, not the main thing.

As far as I understand the proposal the main point for this construct is the use in iterable container classes (implementing a certain interface). And there it can show it's advantages (or what I think that are advantages):

Instead of a very longish (syntax made up just now):

var
   x : IIterable;
   someCollection : TSomeCollection;
   elem : TSomeElement;
[...]
x := (someCollection as IIterable).initIterator();
while (x.hasNextElement()) do begin
	elem := (x.nextElement() as TSomeElement).next();
	<< do something with elem >>
end;
x.doneIterator();
[...]

you could write:

x : TSomeElement;
someCollection : TSomeCollection;

[...]
foreach elem in someCollection do begin
<< do something with elem >>
end;
[...]

which is imo far easier to read. (Please don't mind the word "foreach", I think it's only because it's already used in other languages for that purposes).

The former is also less error prone in regard to using the iterator for the appropriate element (think of nested foreach's). It is typesafe too. It makes it easier to quickly change the actual type of (OO-)container if needed.

And if basic Pascal types (arrays, sets, etc.) were allowed to be used in the same construct, then the programmer won't have to worry about syntax differences in using these basic types and OO-collections too.

E.g.

elem : Integer;
someArray : array[X...Y] of Integer;

[...]
foreach elem in someArray do begin
<< do something with elem, e.g. inc(elem); >>
end;
[...]

or

elem : TSomeEnumeration;
someSet : set of TSomeEnumeration;

[...]
foreach elem in someSet do begin
<< do something with elem >>
end;
[...]

In case of sets this may not only be an abbreviation for the for-loop, but also element testing:

for elem := low(someSet) to high(someSet) do begin
	if (elem in someSet) then begin
		<< dosomething >>
	end;
end;

Probably this also gives some additional opportunities for code optimizations.

But in the end you're right, it's only an abbreviation for already existing functionality; I'd consider it useful though.

Regards,
Thomas

Reply by email

Florian Klaempfl
to Thomas Schatzl
Thomas Schatzl wrote 100 lines
Hello, I think I have to make some things more clear why I am in favor of that "foreach": Thomas Schatzl schrieb: >>> Features being developed now are: >>> MI interfaces 90% (MI=multiple inheritance) >>> Inclasses 15% (embedded classes) >>> foreach 0% (well, we know you hate it) >> >> >> It's a useless statement if used for arrays, enumerations etc. It >> blows up the language for no gain. You are right, for arrays, enumerations etc. there is little to no gain. But I see the application of foreach on these types as added bonus, not the main thing. As far as I understand the proposal the main point for this construct is the use in iterable container classes (implementing a certain interface). And there it can show it's advantages (or what I think that are advantages): Instead of a very longish (syntax made up just now): var x : IIterable; someCollection : TSomeCollection; elem : TSomeElement; [...] x := (someCollection as IIterable).initIterator(); while (x.hasNextElement()) do begin elem := (x.nextElement() as TSomeElement).next(); << do something with elem >> end; x.doneIterator(); [...] you could write: x : TSomeElement; someCollection : TSomeCollection; [...] foreach elem in someCollection do begin << do something with elem >> end; [...] which is imo far easier to read. (Please don't mind the word "foreach", I think it's only because it's already used in other languages for that purposes). The former is also less error prone in regard to using the iterator for the appropriate element (think of nested foreach's). It is typesafe too. It makes it easier to quickly change the actual type of (OO-)container if needed. And if basic Pascal types (arrays, sets, etc.) were allowed to be used in the same construct, then the programmer won't have to worry about syntax differences in using these basic types and OO-collections too. E.g. elem : Integer; someArray : array[X...Y] of Integer; [...] foreach elem in someArray do begin << do something with elem, e.g. inc(elem); >> end; [...] or elem : TSomeEnumeration; someSet : set of TSomeEnumeration; [...] foreach elem in someSet do begin << do something with elem >> end; [...] In case of sets this may not only be an abbreviation for the for-loop, but also element testing: for elem := low(someSet) to high(someSet) do begin if (elem in someSet) then begin << dosomething >> end; end; Probably this also gives some additional opportunities for code optimizations.

Well, I bet people would cry if the iterator works randomly and not element by element :)

But in the end you're right, it's only an abbreviation for already existing functionality; I'd consider it useful though.

I don't like those iterators anyways, they are too unspecific. What happens if you delete element where the iterator points to? What happens, if you delete an element while iterating? Have a look at the STL, it has imo a much better iterator design.

Another problem is probably that people would underestimate the overhead of the foreach statement. I guess you remember the tlist/resourcestring overhead trouble.

Reply by email

Unknown author
to Michael Van Canneyt: I think it is best that you finish your work, and then provide a complete patch. But…

Quoting Michael Van Canneyt :

Like first if it wasn't your last paragraph, I wouldn't even bother to answer. You're obviously taking this thing as pissing contest. (you can spare me about using words like this on mailing list, you last paragraph is worth it, and I don't care if I get banned)

Show quoted text 5 lines
I think it is best that you finish your work, and then provide a complete patch. But please split the patches in separate chunks, so we can clearly distinguish bug-fixes from features.

Finally, answer to something I asked. Even I said it would be better. It was clearly specified. Moving off. I'll probably notify you or not (will have to decide if it is better to make add-on patches for fpc as my own project or trying to go trough this again. Probably the first will win, I appreciate my nerves and time)

No, but it seems to me that you fail to provide good arguments to make us accept the general usefullness of your patches.

Now this bugs me, read my last part of my reply

Usually, when the core developers are not convinced of the usefullness of a feature, it is not implemented or included.

Now this bugs me too, read my last part of my reply

Show quoted text 9 lines
I have not yet seen any argument from your side to convince me that your patches are a useful contribution to the pascal language. That your patches reduce your code base by a factor 4, seems to me an argument that maybe your design is flawed and not that pascal is flawed. Pascal works for me as it is. It works even very well, and I haven't seen a situation where it failed me or I would need any of the features you suggest. So why would it not be so for you ?

Do you need a brief 10 page history, or will you belive me on my word that migrating from language to language defined by my needs is the reason why I can't stuck with pascal. Believe me, I would love to (pascal is still my favourite language).

Obviously you have very limited usage needs for programming.

Take care: I am not suggesting your currently design is actually flawed; But you have not convinced me that your patches are an improvement of the pascal language.

You're not suggesting, you're saying it. And it is not worth to try to move your conviction. (it can't be done with pissing context people, they always win, even if they loose)

Show quoted text 5 lines
For example; MI for interfaces for me is strange (to say the least) because interfaces were introduced to avoid the mess of MI in the first place. So why on earth would you want to introduce it ??

You're too much stuck in pascal. Get out to the world, you might find answer. By the way, when did pascal had MI??? And delphi implementation is the only one that hasn't got MI.

Show quoted text 5 lines
Any contribution is appreciated, but we must be convinced of it's usefullness if it is a feature. If you (or anyone else) fail to make us see that, the patch won't get included. This is a simple fact.

Doesn't look like it. Read last part of my reply

You should not take this personal or whatever, but that is how things work for FPC.

Was not taking it personal. But next paragraph made me take it.

Show quoted text 6 lines
As for the 'is' patch: It is obviously not a simple issue or it would already have been applied. Provide a complete patch, we'll study it, but we cannot guarantee that this will be done fast. The more involved a patch is, the longer it takes to review it, and to estimate possible consequences...

This paragraph made me angry. I provided at least 3 examples (one of them was a complete copy paste and compile) and 1 that was completely wrong. I explained at least 4 times where and how.

I provided both patches complete. refcount (those 3 examples and 4 explanations) and "is" patch. Where it was only said that it does too much. Too much what??? I asked the same question at least 5 times. No answer. If your way of doing is "your software doesn't work, I won't tell you how and where, correct it so I'll like it" then your actions and this last paragraph goes with your principles of work. If you deny that I send it, you can browse trough mail history

But if you try to say that this is not the way you do things around here then go trough mail history.

All I got was a bunch of whining and yapping with my all time favourite "I'm busy with my day time job" (I think I got that from about 3 of you). Well, I guess you haven't been busy enough not answer the question I never asked. Never even considered that instead of yapping about daytime job you could answer the question?

I think I was more than enough tolerant not to burst like this before.

goodbye
ml

Show quoted text 6 lines
Michael. _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/)

Reply by email

Unknown author
to Florian Klaempfl: Well, those 20% cover 80% of interface usage. The most important where interfaces are…

Quoting Florian Klaempfl :

Show quoted text 12 lines
wrote: >>Interfaces are part of 2.0 but mainly to be dephi compatible. >> > > > You mean that 20% of functionality of delphi interfaces that you currently support? Well, those 20% cover 80% of interface usage. The most important where interfaces are used is COM importing and that works usually ;)

And you do that on linux, how???? Being cross portable and all. Interfaces are usable for many other things and COM being not cross portable solution is not one of them.

If I remember you denied quite a few times interfaces that are not equal on all platforms. Where is COM different here?

Meaning 80% usage on Windows and 20% on any other system. Sorry if I don't use or code for or maintain windows machines.

Show quoted text 6 lines
> > So delphi supports operators? and few other objfpc things? No, but those are ancient. The problem is with extensions that they must be maintained as every feature because they get broken from time to time. This is

Ancient, ahhh I see, D9 implemented foreach in classic mode, but you're against that too?

simply experience or just follow up the online testsuite results. Though everybody is careful with its patches, test results get worse if nothing is done. So we're careful with adding new features.

Feature, bugs are now features???? As I recall I reported at least 3 bugs.

As you probably forget. The first time it was mentioned that you're busy preparing for 2.0 (bugs only, but still I wonder why my reports of wrong happening with refcount were not treated so) and not introducing new features I agreed and even suggest that I move off (I didn't wanted to bother you) and contribute just 100% done things that you can test (for next version, and wheter is to your likes) if they suit you.

Up 'till now my only intention was to develop few features, try not to break anything and possibly do it in a way that you could integrate it as easy as possible if you'd like it.

The answer from Michael Van Canneyt changed my intention, I just want to develop it

goodbye
ml

Show quoted text 5 lines
_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/)

Reply by email

Alain Michaud
to Unknown author

FPC/Lazarus is such a nice software. I started using it one year ago. Although they say it is "under development" it works very well!

In addition, there is the comunity... Whenever there is a problem, I can just send an email to the list and often, someone will give me some tips or would even fix the software for me. Try this with Microsoft...

Finally, by reading the discussions on this list, I see "in real time" how the software is being developed and how it slowly evolves towards a most modern software.

Show quoted text 73 lines
Quoting Florian Klaempfl : > wrote: > > >>Interfaces are part of 2.0 but mainly to be dephi compatible. > >> > > > > > > You mean that 20% of functionality of delphi interfaces that you currently > support? > > Well, those 20% cover 80% of interface usage. The most important where > interfaces are used is COM importing and that works usually ;) > And you do that on linux, how???? Being cross portable and all. Interfaces are usable for many other things and COM being not cross portable solution is not one of them. If I remember you denied quite a few times interfaces that are not equal on all platforms. Where is COM different here? Meaning 80% usage on Windows and 20% on any other system. Sorry if I don't use or code for or maintain windows machines. > > > > So delphi supports operators? and few other objfpc things? > > No, but those are ancient. The problem is with extensions that they must be > maintained as every feature because they get broken from time to time. This > is Ancient, ahhh I see, D9 implemented foreach in classic mode, but you're against that too? > simply experience or just follow up the online testsuite results. Though > everybody is careful with its patches, test results get worse if nothing is > done. So we're careful with adding new features. > Feature, bugs are now features???? As I recall I reported at least 3 bugs. As you probably forget. The first time it was mentioned that you're busy preparing for 2.0 (bugs only, but still I wonder why my reports of wrong happening with refcount were not treated so) and not introducing new features I agreed and even suggest that I move off (I didn't wanted to bother you) and contribute just 100% done things that you can test (for next version, and wheter is to your likes) if they suit you. Up 'till now my only intention was to develop few features, try not to break anything and possibly do it in a way that you could integrate it as easy as possible if you'd like it. The answer from Michael Van Canneyt changed my intention, I just want to develop it goodbye ml > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal > ---------------------------------------------------------------------- This mail sent through Horde-Toaster (http://qmailtoaster.clikka.com/) _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Thomas Schatzl
to Florian Klaempfl: Well, I bet people would cry if the iterator works randomly and not element by element :)…

Hello,

Show quoted text 6 lines
> >Probably this also gives some additional opportunities for code >optimizations. Well, I bet people would cry if the iterator works randomly and not element by element :)

Don't know why you're so focused at this point, but certainly, yes, they would =) but as I already mentioned, there's nothing against defining a "natural" iteration order for certain types which of course must be preserved during optimization. And this was just an idea.
Maybe I'm misunderstanding you too, I'm not proposing optimizations which change iteration order (where it hurts, e.g. for arrays). In that specific cases more things like e.g. automatically knowing that any internal indices can never be referenced by the program.
If this answer is not sufficient, I'd like to ask you to explain what you meant in other words; probably my English is too bad to understand you here, sorry.

Show quoted text 6 lines
>But in the end you're right, it's only an abbreviation for already >existing functionality; I'd consider it useful though. I don't like those iterators anyways, they are too unspecific. What happens if you delete element where the iterator points to? What happens, if you delete an element while iterating?

From what I read about STL problems (some forums, some tutorials), the STL iterator doesn't care about element deletion and element removal at all, their value must be considered unusuable after a structural modification of the container (and partially from what I see from simple element modification :).
And there's also no indication of some notification returned if the iterator is accessed after a structural modification. So the STL doesn't give a good example in this matter too.

For the unspecificness: well, we're currently discussing the options, don't we? My suggestion was to simply use the "compatible" way of Delphi/.NET as far as I remember it (which is specified and easily accessable via the web). But in the end I think it's manageable to get at least the same behaviour as the STL - by simply not caring about that at all... :-)

Please correct me if I'm wrong, if possible with some definite reference, couldn't find one.

Have a look at the STL, it has imo a much better iterator design.

You're right, STL iterators are more powerful, but this is not because of their representation or their safety, but due to their other functionality not needed in this case. All those functions (even this comparison stuff) could be implemented using iterator interfaces (similar to STLs iterator types) and operators as well imo. Or similar to STL there's the possibility of using an iterator object. The IIterator _interface_ as used was just a proposal, which was given because Delphi/.NET has a similar one.
The other drawback I can see is mostly due to FPC not having generics
- certainly taking this into account this proposal is _really_ inferior, but better than nothing atm. And as soon as FPC supports generics, they can be used to remove unneeded dynamic type checks too.

Maybe somebody else has more insight in the STL or knows other iterator implementations for more ideas.

Either way, the original point was foreach after all, which is just a shorthand for a special type of traversal, using a special type of iterator (STL lingo: forward-iterator). It doesn't *need* a complete STL to do that.
It's definitely not the ultimate concept solving every problem either ;)

Another problem is probably that people would underestimate the overhead of the foreach statement.

I don't see any overhead for basic types, since it's more or less an advanced macro for a "for i := low(array) to high(array) do ...". And in OO element access usually means calling some read method or some similar (forward-)iterator (in STL-lingo) method anyway... (even STL iterator methods result in method calls in the end) This is in my experience the case for at least anything else than a simple list backed up by an array (Borland's TList) where you can directly access the element via indices; and if you actually care about OO programming, e.g. doing information hiding.
It's not slower than doing it manually either, or am I wrong?

I guess you remember the list/resourcestring overhead trouble.

If I may ask, what was the problem with tlist/resourcestring issue again? As far as I can remember, the real problem was something about FPC creating too much/inefficient exception support code, and/or the exception code generated by FPC optimizes for the (uncommon) exception case which slows down the app in the (common) non-exception case too (which is not needed).
I don't see the connection here right now.

You, as programmer, have the responsibility to choose the appropriate data structure for your task - definitely nothing new. This won't change that easily =)

Regards,
Thomas

Reply by email

Marco van de Voort
to Thomas Schatzl: I think I have to make some things more clear why I am in favor of that "foreach": You…
Show quoted text 34 lines
the main thing. As far as I understand the proposal the main point for this construct is the use in iterable container classes (implementing a certain interface). And there it can show it's advantages (or what I think that are advantages): Instead of a very longish (syntax made up just now): var x : IIterable; someCollection : TSomeCollection; elem : TSomeElement; [...] x := (someCollection as IIterable).initIterator(); while (x.hasNextElement()) do begin elem := (x.nextElement() as TSomeElement).next(); << do something with elem >> end; x.doneIterator(); [...] you could write: x : TSomeElement; someCollection : TSomeCollection; [...] foreach elem in someCollection do begin << do something with elem >> end; [...]

True, BUT... hmm, I actually have 3 BUTS

BUT 1: some form shorter syntax can be thought up for _each_ _and_ _every_ construct. That is the danger of syntactic sugar, it always looks tempting as a shorthand. However if you indulge in it, you get Perl. If there is a valid normal construct, and that is not extremely larger, than you don't need it.

BUT 2: The whole purpose of iterators is that you can have multiple orders on the same object, and get a different iterator to get a different order. The syntax does not allow this. Typical ss.

BUT 3: I myself currently use iterators at work (modeled after decal, except without the variant-interface stuff, because of performance) and your example looks overly verbose;

var iter:dlightmapiterator;
iter:=lightmapstartiter(collection);
while lightmapiterateover(iter) do
 << do something with getobject(iter)>>
// no finalisation of iter necessary.

Is this so bad ? I don't see the problem

which is imo far easier to read. (Please don't mind the word "foreach", I think it's only because it's already used in other languages for that purposes).

IMHO it sucks. Write a code template for your IDE if you really want to spare out those 10 key strokes.

Reply by email

Thomas Schatzl
to Marco van de Voort

Hello,

Show quoted text 12 lines
>you could write: > >x : TSomeElement; >someCollection : TSomeCollection; > >[...] >foreach elem in someCollection do begin > << do something with elem >> >end; >[...] True, BUT... hmm, I actually have 3 BUTS

It is some sort of syntactic sugar, so all your but's are valid at least in some way. Nobody ever doubted this.

Show quoted text 5 lines
BUT 1: some form shorter syntax can be thought up for _each_ _and_ [...] BUT 2: The whole purpose of iterators is that you can have multiple orders on the same object, and get a different iterator to get a different order.

I disagree, the main purpose of iterators is to provide uniform iteration over containers (e.g. to use the same code to iterate over different collections).
That there are different types of iterators (forward, backward, and random access, readonly, writeable, ...) is definitely a feature of a specific iterator imo.

If you have to program differently for every container (for i := low(x)
to ..; for i := 0 to count-1 ...; etc. etc.) only makes code harder to
understand and error prone without additional gain.

Additionally if you examine code, _far_ the most applications do simple forward (and maybe backward) iteration over a collection (also because there are not that much collections where random access makes sense runtime-wise).

So maybe it is feasible to enhance the syntax to the following (BNF this time):

foreachstatement ::=
"foreach" element "in" container ["forwards" | "backwards"] "do" statement.

or:

foreachstatement ::=
"foreach" element "in" typed-range-expression "do" statement.

typed-range-expression ::=
   container "'" range-expression.
range-expression ::= first-element-spec ".." last-element-spec.

and first-element and last-element being a specification of those. This can be for arrays: bottom and last element (greetings from e.g. VHDL/ADA?, see for more details there), for OO containers a specification of two iterators indicating position, see STL. But this may be total overkill for the typical application.

*ducks into cover, awaiting flames* =)

The syntax does not allow this. Typical ss.

You are right, it _is_ syntactic sugar. Never doubted it. But iterators may be an important tool in programming which may justify inclusion into the language.

Show quoted text 12 lines
BUT 3: I myself currently use iterators at work (modeled after decal, except without the variant-interface stuff, because of performance) and your example looks overly verbose; var iter:dlightmapiterator; iter:=lightmapstartiter(collection); while lightmapiterateover(iter) do << do something with getobject(iter)>> // no finalisation of iter necessary. Is this so bad ? I don't see the problem

I'm not sure that I'm interpreting your code sequence correctly, but I don't consider this design as very good either (maybe driven by implementation considerations though) - you lost abstraction over the container type which forces the programmer to learn the correct commands for every type of container (which isn't too hard assuming that they are pretty similar - but there is no real *gain* for doing that. And you don't lose anything when you do it the other way)

The finalization is a pure design issue, depending on the capabilities of the container (thread safety, safe for container modification, ...) which may be needed to properly release used resources. This is an option.

Additionally you lost type safety (e.g. missing the typecast of the retrieved object =).

Taking all that into account there isn't much difference in typing between the two proposals, isn't there?

Show quoted text 6 lines
>which is imo far easier to read. (Please don't mind the word "foreach", >I think it's only because it's already used in other languages for that >purposes). IMHO it sucks. Write a code template for your IDE if you really want to spare out those 10 key strokes.

:-)

Regards,
Thomas

Reply by email

Thomas Schatzl
to Michael Van Canneyt: I think it is best that you finish your work, and then provide a complete patch. But…

Hello,

For example; MI for interfaces for me is strange (to say the least) because interfaces were introduced to avoid the mess of MI in the first place. So why on earth would you want to introduce it ??

Because MI itself isn't bad, it's often an appropriate representation of some abstract model. There's only the problem when there are different implementations for the same method, that's why it is generally avoided. This is multiple _implementation_ inheritance. Commonly considered bad =)

Since interfaces do not have/inherit implementations by definition this is not an issue, they simply aggregate function *specifications* (no code). This is multiple _interface_ inheritance. Commonly considered good =)

Effectively it cuts down typing involved in creating interface hierarchies dramatically, or actually enabling some things. Another thing that comes to my mind is that it allows some clever tagging with empty interfaces (without saying anything of importance).

Example (probably not ideal, but I hope mostly self-explaining):

type
IInput = interface
... method specifications ...

   end;
  IOutput = interface
     ... method specifications ...
  end;
  IInOut = interface(Input, Output)
     ... method specifications ...
  end;
  IBlockdeviceReaderWriter = interface(IInout, ...)
     ... method specifications ...
  end;
  IStreamedReaderWriter = interface(IInout, ...)
    ... method specifications ...
  end;
  TSomeClass = class(<ancestorA>, IBlockdeviceReaderWriter)
    ... method specs + implementations ...
  end;
  TSomeOtherClass = class(<ancestorB>, IStreamReaderWriter)
  end;
  [...]

- You can use both TSomeClass and TSomeOtherClass in methods using an IInOut now, this includes easy testing that TSomeClass and TSomeOtherClass have the required capabilities by

var instance : either TSomeClass or TSomeOtherClass;
SomeProcessingMethod(x : IInout);
   and
SomeProcessingMethod(x as IInout);

Not

SomeProcessingMethod(x : TObject);
   and
SomeProcessingMethod(x);

and test that x implements both IOut and IIn before using it in the method (or before calling the method, or using overloading in some cases).

Still both implementations retain the flexibility of being allowed to be derived some different ancestors _if needed and appropriate_.

- if you add a subinterface to IInOut you'd have to revise all your code and add this interface to all class specifications... I don't hope you forget one (since the "as" is evaluated at compile time, happy bug hunting).

- tagging of instances with (empty) interfaces and use of existing methods for checking.

type
	IMammal = interface;
	IMeatEater = interface;
	IPlantEater = interface;
	IEatsEverything = interface(IMeatEater, IPlantEater);
	IRat = interface(IMammal, IEatsEverything);

Checking an instance for being a rat (implementing IRat) is just a matter of "supports(instance, IRat)", not necessarily "supports(instance, IMammal) and supports(instance, IMeatEater) and supports(instance, IPlantEater)".

In Pascal sets may be used for that. But consider that every one of those interfaces specifies one or more particular methods... (maybe this example is better than the above one after all). There's no way other than dirty tricks(*1) to make sure that the instance implements a method which is called according to the interface type (and actually call it!).

The classes implementing these interface still must implement the methods (*once* for every class hierarchy build). But they don't need to have a common ancestor. (Using decorators you can employ those though).

*1: my best bet would be defining a common abstract class providing all methods in an abstract way, and the successors implementing this one partially. From the design pov this is not a good idea...

I hope this somewhat gives you an idea of the capabilites of this feature.

(Actually COM interfaces can be considered somewhat degenerate in that aspect)

----------------

Btw, also D8 supports it:

http://bdn.borland.com/article/0,1410,29779,00.html

I don't see a reason why there's an ambiguous call error in the example (I think this is due to implementation restrictions/compatibility issues) - after all there is only one implementation for ICombo available.

Btw, D8+ also supports "as" between two interfaces as seen from the example.

Regards,
Thomas

Reply by email

Thomas Schatzl
to Thomas Schatzl

Hello,

Show quoted text 11 lines
Michael Van Canneyt schrieb: > For example; > MI for interfaces for me is strange (to say the least) because > interfaces were introduced to avoid the mess of MI in the first > place. So why on earth would you want to introduce it ?? Since interfaces do not have/inherit implementations by definition this is not an issue, they simply aggregate function *specifications* (no code). This is multiple _interface_ inheritance. Commonly considered good =)

Maybe an elaboration of the Rat-example (well, grew to a mouse-example :) helps to clarify some problems you have with interface-MI:

I marked the comments which talk about advantages this feature gives the programmer with "(+)"

type
     TWasAcceptable = Boolean;
     IMammal = interface
        procedure sleep(); // a mammal can sleep
     end;
     IMeatEater = interface
         // a meat eater can eat
        function eat(m : TMeal) : TWasAcceptable;
     end;
     IPlantEater = interface
         // a plant eater can eat too
     	function eat(m : TMeal) : TWasAcceptable;
     end;
     // something that can eat both plants and meat
     IEatsEverything = interface(IMeatEater, IPlantEater);
     IJumping = interface
        procedure jumparound();
     end;
     // a mouse can sleep, eat something and wiggle with its
     // tail (and certainly much more =)
     IMouse = interface(IMammal, IEatsEverything)
        procedure wiggleWithTail();
     end;

Now I have several types of mice:

     // a mouse can do everything what a mouse is supposed to do
     // this class _implements_ the abilities
     TMouse = class(TAnimal, IMouse)
        procedure sleep();
        procedure eat(m : TMeal);
        procedure wiggleWithTail();
     end;

(+) Don't need to specify that TMouse implements IMammal, IPlantEater, IMeatEater and 10 other interfaces as well. I hope you don't forget one. Can be "remedied" by a hierarchy of singly inherited interfaces, e.g. IPlantEatingMammal, IMeatEatingMammal, IAllEatingMammal, IMouseMammal, IJumpingMouseMammal, ...

     // for example's sake although Micky Mouse looks like a mouse
     // and can do the same things as the animal with the same
     // name it is not derived from TMouse (it is not an animal
     // after all)
     TMickeyMouse = class(TCartoonCharacter, IMouse, IJumping)
        procedure sleep();
        procedure eat(m : TMeal);
        procedure wiggleWithTail();
        procedure jumparound();
     end;

[...]
Implement methods of classes. Certainly in completely different ways - while the mouse animal accepts maybe rotten meat, Mickey Mouse may not, but it eats edible meals. Maybe due to the ancestors (single inheritance!) the methods are already partially implemented as well. [...]

(+) You may notice that although there's a name clash in the interface specification. Does not matter at _all_, because it's only a specification, e.g. "has that method, don't care how it's implemented" (***).
(+) There's no problem with instantiation either because you simply do _not_ instantiate 's only a specification of what
this type can do.

In the code using these classes I can now use instances of both classes (no news here, you could that with single inherited interfaces too).

E.g.
// gives *any* plant eater a meal to eat. Consider we have some cow
// class which implements IPlantEater as well (and hence can eat too!)
procedure eat_a_plant(obj : IPlantEater; plant : TPlantMeal);
...
// gives the given object a meal. Since this is a generic meal, only
// objects which can eat everything can eat here. No need to check
// further in the code of the procedure whether the meal is of meat or
// plant type, we can be sure it accepts it.
procedure eat_just_something(obj : IEatsEverything; meal : TMeal);
...

(+)Can't do that with singly inherited interfaces... (in this case it might be reasonable to check whether the meal is edible for planteaters/meateaters and maybe throw an exception) but actually it'd be natural.
Consider the case when there's not only two types of things animal can eat... remember that case'ing doesn't work with interfaces. (+) Again: The fact that IEatseverything is multiply inherited (and the method signatures overlap) does not even matter. Interfaces are just specifications which are always bound on runtime....

// gives the mouse a meal and forces tail wiggling if it was
// acceptable
procedure eat_some_meat_and_wiggle_with_tail_if_ok(obj : IMouse; meat :
TMeal);
...
// lets the given mammal walk around
procedure walkaround(obj : IMammal);
...

-------
What happens if you add another completely different animal?

IFish = interface
	procedure swim();
end;
IShark = interface(IFish, IEatsEverything);
TShark = class(TFish, IShark)
	procedure swim();
         procedure eat(m : TMeal);
end;

.... any method (which were originally designed for the hierachy of mammals) still work. You can feed the shark independent of being a shark (only interested that it can eat everything you throw at it). You can easily check whether the given object is a fish, or whether it has _all_ properties of a shark, or something else.

This can be more or less done with single interface inheritance too.

Now I am going to add some property to all sharks, say that it has a natural killer instinct (don't let that property's name bother you, inventing something reasonably okay is hard ;-).

e.g.
   INaturalKiller = interface;

and change IShark to

   IShark = interface(IFish, IEatsEverything, INaturalKiller);

(+) Recompile. Now every instance can be checked whether it has that INaturalKiller property easily, without further code modifications (with singly inheritance you'd now be starting to invent names for more combinations... or design everything with a set in a common base class to be able to use it reasonably well in an OO sense (which requires you to find some common base class, maybe TAnimal. But that doesn't work very often)

----------------

Summing MI with interfaces up:
- interfaces are only specifications, so there is no clash of implementations
- they neither have some initialization, so there's no problem about constructing the instance either
- they provide means to model your world naturally

Regards,
Thomas

(***) there are different possibilities resolving this "conflict". Some languages treat it as conflict (where logically there isn't), e.g. C# (solved via the "implements" directive in Delphi8+ I assume), others see no conflict, e.g. Java.
Implementation is straightforward in the latter case (already done by ml), maybe some more thoughts needed for the former.

Reply by email

Michael Van Canneyt
to Thomas Schatzl
Thomas Schatzl wrote 171 lines
Hello, Thomas Schatzl schrieb: > Michael Van Canneyt schrieb: > > > For example; > > MI for interfaces for me is strange (to say the least) because > > interfaces were introduced to avoid the mess of MI in the first > > place. So why on earth would you want to introduce it ?? > > Since interfaces do not have/inherit implementations by definition this > is not an issue, they simply aggregate function *specifications* (no > code). This is multiple _interface_ inheritance. Commonly considered good > =) Maybe an elaboration of the Rat-example (well, grew to a mouse-example :) helps to clarify some problems you have with interface-MI: I marked the comments which talk about advantages this feature gives the programmer with "(+)" type TWasAcceptable = Boolean; IMammal = interface procedure sleep(); // a mammal can sleep end; IMeatEater = interface // a meat eater can eat function eat(m : TMeal) : TWasAcceptable; end; IPlantEater = interface // a plant eater can eat too function eat(m : TMeal) : TWasAcceptable; end; // something that can eat both plants and meat IEatsEverything = interface(IMeatEater, IPlantEater); IJumping = interface procedure jumparound(); end; // a mouse can sleep, eat something and wiggle with its // tail (and certainly much more =) IMouse = interface(IMammal, IEatsEverything) procedure wiggleWithTail(); end; Now I have several types of mice: // a mouse can do everything what a mouse is supposed to do // this class _implements_ the abilities TMouse = class(TAnimal, IMouse) procedure sleep(); procedure eat(m : TMeal); procedure wiggleWithTail(); end; (+) Don't need to specify that TMouse implements IMammal, IPlantEater, IMeatEater and 10 other interfaces as well. I hope you don't forget one. Can be "remedied" by a hierarchy of singly inherited interfaces, e.g. IPlantEatingMammal, IMeatEatingMammal, IAllEatingMammal, IMouseMammal, IJumpingMouseMammal, ... // for example's sake although Micky Mouse looks like a mouse // and can do the same things as the animal with the same // name it is not derived from TMouse (it is not an animal // after all) TMickeyMouse = class(TCartoonCharacter, IMouse, IJumping) procedure sleep(); procedure eat(m : TMeal); procedure wiggleWithTail(); procedure jumparound(); end; [...] Implement methods of classes. Certainly in completely different ways - while the mouse animal accepts maybe rotten meat, Mickey Mouse may not, but it eats edible meals. Maybe due to the ancestors (single inheritance!) the methods are already partially implemented as well. [...] (+) You may notice that although there's a name clash in the interface specification. Does not matter at _all_, because it's only a specification, e.g. "has that method, don't care how it's implemented" (***). (+) There's no problem with instantiation either because you simply do _not_ instantiate 's only a specification of what this type can do. In the code using these classes I can now use instances of both classes (no news here, you could that with single inherited interfaces too). E.g. // gives *any* plant eater a meal to eat. Consider we have some cow // class which implements IPlantEater as well (and hence can eat too!) procedure eat_a_plant(obj : IPlantEater; plant : TPlantMeal); ... // gives the given object a meal. Since this is a generic meal, only // objects which can eat everything can eat here. No need to check // further in the code of the procedure whether the meal is of meat or // plant type, we can be sure it accepts it. procedure eat_just_something(obj : IEatsEverything; meal : TMeal); ... (+)Can't do that with singly inherited interfaces... (in this case it might be reasonable to check whether the meal is edible for planteaters/meateaters and maybe throw an exception) but actually it'd be natural. Consider the case when there's not only two types of things animal can eat... remember that case'ing doesn't work with interfaces. (+) Again: The fact that IEatseverything is multiply inherited (and the method signatures overlap) does not even matter. Interfaces are just specifications which are always bound on runtime.... // gives the mouse a meal and forces tail wiggling if it was // acceptable procedure eat_some_meat_and_wiggle_with_tail_if_ok(obj : IMouse; meat : TMeal); ... // lets the given mammal walk around procedure walkaround(obj : IMammal); ... ------- What happens if you add another completely different animal? IFish = interface procedure swim(); end; IShark = interface(IFish, IEatsEverything); TShark = class(TFish, IShark) procedure swim(); procedure eat(m : TMeal); end; .... any method (which were originally designed for the hierachy of mammals) still work. You can feed the shark independent of being a shark (only interested that it can eat everything you throw at it). You can easily check whether the given object is a fish, or whether it has _all_ properties of a shark, or something else. This can be more or less done with single interface inheritance too. Now I am going to add some property to all sharks, say that it has a natural killer instinct (don't let that property's name bother you, inventing something reasonably okay is hard ;-). e.g. INaturalKiller = interface; and change IShark to IShark = interface(IFish, IEatsEverything, INaturalKiller); (+) Recompile. Now every instance can be checked whether it has that INaturalKiller property easily, without further code modifications (with singly inheritance you'd now be starting to invent names for more combinations... or design everything with a set in a common base class to be able to use it reasonably well in an OO sense (which requires you to find some common base class, maybe TAnimal. But that doesn't work very often) ---------------- Summing MI with interfaces up: - interfaces are only specifications, so there is no clash of implementations - they neither have some initialization, so there's no problem about constructing the instance either - they provide means to model your world naturally

All this is nice, but it boils down to: MI for interfaces is shorthand notation. No more, no less. It introduces no added value (other than notational) or functionality.

I find it more clear to have
if (A is IA) and (A is IB) then
..
Instead of

If (A is IC) then
  ..

Where IC would simply be IA and IB conmbined. In IC, you hide what actually is. (the names are not always as descriptive as in your example.)

If you need to check for IA and IB regularly in your code, then it is easy to write a general-purpose function

Function SupportsInterfaces(A : TInterfacedObject; Interfaces : Array of Interface) : Boolean;

And then write

if SupportsInterfaces(A,[IA,IB]) then

Which is much more explicit about the properties you are actually querying.

Also, if your component needs more than, say, 5 interfaces, then I think you need to do some serious rethinking of your design. Even in OpenOffice (one of the more elaborate collections of interfaces I've encountered so far) there are few objects with SO many interfaces.

So, KIS (Keep it Simple) is the principle.
Which is the computer variant of science's "Ockham's razor":

''Pluralitas non est ponenda sine neccesitate'',
which translates as
``entities should not be multiplied unnecessarily''.

The latin is rather fitting for computer language IMHO :-)

Michael.

Reply by email

Florian Klaempfl
to Thomas Schatzl: It is some sort of syntactic sugar, so all your but's are valid at least in some way.…
Thomas Schatzl wrote 5 lines
Additionally if you examine code, _far_ the most applications do simple forward (and maybe backward) iteration over a collection (also because there are not that much collections where random access makes sense runtime-wise).

There come a lot in my mind: e.g. containers using internally trees there "pre node" processing is cachewise usefull, "spare" sets, containers using linked list to represent data internally etc.

Show quoted text 26 lines
So maybe it is feasible to enhance the syntax to the following (BNF this time): foreachstatement ::= "foreach" element "in" container ["forwards" | "backwards"] "do" statement. or: foreachstatement ::= "foreach" element "in" typed-range-expression "do" statement. typed-range-expression ::= container "'" range-expression. range-expression ::= first-element-spec ".." last-element-spec. and first-element and last-element being a specification of those. This can be for arrays: bottom and last element (greetings from e.g. VHDL/ADA?, see for more details there), for OO containers a specification of two iterators indicating position, see STL. But this may be total overkill for the typical application. *ducks into cover, awaiting flames* =)

No, these ideas I like much more than a plain foreach statement. Though I think implementing this using interfaces makes no use for me because usually interfaces pulls in too much overhead so it doesn't scale very well. Just look at the compiler, there are a lot of linked lists used like:

p:=first;
while assigned(p) do
  begin
    ...
    p:=p^.next;
  end;

while the list in a lot of cases has only one element.

Reply by email

Marco van de Voort
to Thomas Schatzl: It is some sort of syntactic sugar, so all your but's are valid at least in some way.…
Show quoted text 8 lines
>> << do something with elem >> >>end; >>[...] > > True, BUT... hmm, I actually have 3 BUTS It is some sort of syntactic sugar, so all your but's are valid at least in some way. Nobody ever doubted this.

Good.

Show quoted text 12 lines
> BUT 1: some form shorter syntax can be thought up for _each_ _and_ > [...] > > BUT 2: The whole purpose of iterators is that you can have multiple orders >on the same object, and get a different iterator to get a different order. I disagree, the main purpose of iterators is to provide uniform iteration over containers (e.g. to use the same code to iterate over different collections). That there are different types of iterators (forward, backward, and random access, readonly, writeable, ...) is definitely a feature of a specific iterator imo.

I'm more thinking on different properties. E.g. on address, on name etc.

If you have to program differently for every container (for i := low(x) to ..; for i := 0 to count-1 ...; etc. etc.) only makes code harder to understand and error prone without additional gain.

I don't buy that kind of arguments. This is Pascal, not Matlab. You need to have a general idea about is what happening, and knowledge about typing is a fundament of a strongly typed language. Note that I name Matlab and not VB. Contrary to popular myth, you need to have a pretty good sense about what is happening in VB too, at least if your program is non-trivial.

Additionally if you examine code, _far_ the most applications do simple forward (and maybe backward) iteration over a collection (also because there are not that much collections where random access makes sense runtime-wise).

My point was that if you invent syntax, at least make it somewhat general. However that is pretty much the point of this extension. A few people knew this construct from VB, which has no sane syntax anyway, and complained about the two extra keystrokes. It has nothing to do with design or thinking about a nice, general solution.

Show quoted text 6 lines
So maybe it is feasible to enhance the syntax to the following (BNF this time): foreachstatement ::= "foreach" element "in" container ["forwards" | "backwards"] "do" statement.

foreach element in container[.interface] do
statement

with interface the a property that returns an interface to the iterator, one being default

However this is all just trying to find justification to implement it. I brought the point up to show that the syntax wasn't really thought about, just plain copied.

*ducks into cover, awaiting flames* =)

IMHO this time to find arguments to justify something stupid as for..each and MI interfaces should better be invested in researching a documenting a possible implementation for generics. At least that opens a scala in possibilities, and is not simply trying to avoid two keystrokes of typing, that could be solved with an IDE macro/template anyway.

You are right, it _is_ syntactic sugar. Never doubted it. But iterators may be an important tool in programming which may justify inclusion into the language.

Then come with a nice library design that does iterators in a sane way. With possible extensions. Then we might have a sane talk about it.

Show quoted text 13 lines
> while lightmapiterateover(iter) do > << do something with lightmapgetobject(iter)>> > // no finalisation of iter necessary. > > Is this so bad ? I don't see the problem I'm not sure that I'm interpreting your code sequence correctly, but I don't consider this design as very good either (maybe driven by implementation considerations though) - you lost abstraction over the container type which forces the programmer to learn the correct commands for every type of container (which isn't too hard assuming that they are pretty similar - but there is no real *gain* for doing that. And you don't lose anything when you do it the other way)

You might notice that the names are exactly DECAL notation with type prefixed. However decal (an interface based implementation) was painfully slow. A decal <string,objects> map is slower than a sorted tstringlist, which is already not really a performance wonder.

The finalization is a pure design issue, depending on the capabilities of the container (thread safety, safe for container modification, ...) which may be needed to properly release used resources. This is an option.

Indeed.

Additionally you lost type safety (e.g. missing the typecast of the retrieved object =).

There is only one solution for that. Generics. Not a custom solution for every point were it might occur.

Taking all that into account there isn't much difference in typing between the two proposals, isn't there?

IMHO not in all three, since it is all invoking a template to me :)

Reply by email

Thomas Schatzl
to Marco van de Voort

Hello,

Show quoted text 5 lines
>That there are different types of iterators (forward, backward, and >random access, readonly, writeable, ...) is definitely a feature of a >specific iterator imo. I'm more thinking on different properties. E.g. on address, on name etc.

I don't understand that remark right now, but it sounds interesting (maybe because it's late). Care to explain that briefly? (Or give a reference)

I don't buy that kind of arguments. This is Pascal, not Matlab. You need to have a general idea about is what happening, and knowledge about typing is a fundament of a strongly typed language.

I don't agree to this argument that this needs to reflect in the syntax (your argument is "this is Pascal and that's it"). The type of a container is the specification after the double colon, not the loop structure/syntax. It does not disallow the traditional way either; all components used (container, element) in this syntax are properly typed, and it does not weaken typing at all.

Show quoted text 5 lines
My point was that if you invent syntax, at least make it somewhat general. However that is pretty much the point of this extension. A few people knew this construct from VB, which has no sane syntax anyway, and complained about the two extra keystrokes. It has nothing to do with design or thinking about a nice, general solution.

and

>*ducks into cover, awaiting flames* =) IMHO this time to find arguments to justify something stupid as for..each

You are right in these aspects; I'm not the person who cares much about that "foreach" either. That means that I can happily live without it and don't care about this syntax which is lacking usefulness, so I accept and actually agree to this decision in the end.

Regards,
Thomas

Reply by email

Thomas Schatzl
to Michael Van Canneyt: All this is nice, but it boils down to: MI for interfaces is shorthand notation. No more,…

Hello,

Show quoted text 13 lines
On Thu, 7 Apr 2005, Thomas Schatzl wrote: > >Summing MI with interfaces up: >- interfaces are only specifications, so there is no clash of implementations >- they neither have some initialization, so there's no problem about >constructing the instance either >- they provide means to model your world naturally All this is nice, but it boils down to: MI for interfaces is shorthand notation. No more, no less. It introduces no added value (other than notational) or functionality.

You suggest that you simply treat the interfaces seperately and use clever single inheritance to simulate all that stuff by clever thought out checks.

In short: that's plain stupid (Please forgive me for that and please tell me that you meant something else).

Long version: it works if you're a really quick typist:

- you add lots of tiny mini-interfaces (actually _all_ interfaces which can be reached by that particular root node) to the list of implemented interfaces. Bad. Obsfucating code. What was the idea with inheritance again? Updating all that stuff when changing the hierarchy is hopefully done magically.
- regarding checks: if you change the hierarchy, you need to revisit all of your checks in the code whether they are reflected properly in the hierarchy. Do you really believe anyone will check and update a few hundred kb of code with tons of such checks, and test them all again?
- additionally, to be truely equal, all ancestors must manually aggregate all methods of child interfaces (otherwise you don't get the same functionality, look at the eat_just_something() example again). Changing the hierarchy comes to my mind again...
- you can optimize (e.g. so that you don't need to aggregate method names by hand) the hierarchy manually by defining single inheritance paths through the MI hierarchy (for every leaf node one, additional if there are diamond shapes in the hierarchy). But this leads to the problem that you actually need additional interface names "IJumpingMouseEatsEverythingMeatEaterPath" and
"IJumpingMouseEatsEverythingPlantEaterPath" are _really_ descriptive, don't you think too? Wasn't it you who was complaining about good naming...? What about hierarchy change again?
- you might need additional paths for the other examples to work (stopped counting here, numbers got too high).

This may work for a model hierarchy of five interfaces in total (and even then you do not do it that way).
Actually already really small OO-models easily have over thirty interfaces with all kinds of inheritance relations. Larger ones I know have a few hundred (e.g. CWM, MOF, UML).

Note to myself: I should give "real world" models as examples next time, not a carefully cleaned up one... people might start thinking that the problem is exactly like this, only with changed names.

Where IC would simply be IA and IB conmbined. In IC, you hide what actually is. (the names are not always as descriptive as in your example.)

This is not a problem of MI-inherited interfaces, but a problem of the programmer. You can do bad naming everywhere and anytime. It's simply the designer's job to do this properly, a good design includes good naming. Btw, interface MI actually requires exactly the same amount or less names, for every interface exactly one (because otherwise you won't get the same functionality).

[Btw. same argument applies for single inheritance, every additional level "hides" the methods the ancestor implements in the same way. Is single inheritance bad because of that now?]

Show quoted text 19 lines
I find it more clear to have if (A is IA) and (A is IB) then .. Instead of If (A is IC) then .. If you need to check for IA and IB regularly in your code, then it is easy to write a general-purpose function Function SupportsInterfaces(A : TInterfacedObject; Interfaces : Array of Interface) : Boolean; And then write if SupportsInterfaces(A,[IA,IB]) then Which is much more explicit about the properties you are actually querying.

This is maybe more "explicit" for two interfaces, or maybe five. But please do _not_ tell me that for a hundred interface hierarchy (ok, you probably won't have to check all hundred at once).

The compiler won't help you here, because he does not know that IA and IB have a logical connection and can't warn you that a (potentially) new ID is somehow related to IA and IB too and you missed it.

Outright unrealistic what you suggest.

Also, if your component needs more than, say, 5 interfaces, then I think you need to do some serious rethinking of your design. Even in OpenOffice (one of the more elaborate collections of interfaces I've encountered so far) there are few objects with SO many interfaces.

It's not the number of interfaces the object actually exposes, it's the number of interfaces and the hierarchy itself which requires the "shorthand notation".

I don't know OOo code, or what particular part of the code you refer to, but I think I am able to counter your argument anyway:

What I know for sure is that in the Java-world (and likely similar in the .NET world) interface MI is commonly used (even in the API). See the web, grab some projects and see (remember, the _number_ of interfaces in the hierarchy is relevant here, not what's actually exposed to the user).

If you refer to the C++ code: your observation is quite easily explained, COM-interfaces don't allow interface MI so you will never get a high *interface* count there (not even C programmers are that stupid). Additionally C++ doesn't require interface MI (or interfaces in this sense) at all, it already has implementation MI which is more powerful. So the programmers following KIS only exactly export the COM-ones which you can see and not a single more.
So an indicator for possible application of MI in C++ code is the amount of implementation MI usage; I know for sure that this is generally quite high... exactly to have a good model, and cut down code size to reasonable levels.
If you want to get a feeling of how much MI is actually used, just grab a medium sized C++ library.

Seems like the Java, .NET and C++ community "needs some serious rethinking of their design" soon.
And I need a very fast typer right now. Michael, do you have some spare time?

So, KIS (Keep it Simple) is the principle.

I'm currently asking myselves why I'm actually typing on a keyboard. I mean, punching cards were fine too... simple, easy, and actually working.

Show quoted text 7 lines
Which is the computer variant of science's "Ockham's razor": ''Pluralitas non est ponenda sine neccesitate'', which translates as ``entities should not be multiplied unnecessarily''. The latin is rather fitting for computer language IMHO :-)

Yes, yes, I get the idea and simply use another language for these things (if you don't want to apply for the typist position, that is ;-).

Regards,
Thomas

*rofl*

Reply by email

Marco van de Voort
to Thomas Schatzl: I don't understand that remark right now, but it sounds interesting (maybe because it's…
Show quoted text 10 lines
Marco van de Voort schrieb: >>That there are different types of iterators (forward, backward, and >>random access, readonly, writeable, ...) is definitely a feature of a >>specific iterator imo. > > I'm more thinking on different properties. E.g. on address, on name etc. I don't understand that remark right now, but it sounds interesting (maybe because it's late). Care to explain that briefly? (Or give a reference)

You were thinking too implementation specific. A container object is something with access to other containers, no order enforced. So it can multiple orders.

E.g. if your object is a clientdataset or so, you can simply select a different index, and iterate over a different field of your business object.

Show quoted text 6 lines
> I don't buy that kind of arguments. This is Pascal, not Matlab. You > need to have a general idea about is what happening, and knowledge about > typing is a fundament of a strongly typed language. I don't agree to this argument that this needs to reflect in the syntax (your argument is "this is Pascal and that's it").

No it isn't. The argument is "This is Pascal, and you are expected to have at least a vague idea about how it works, and it is strongtyped so you are expected to at least grasp the idea of typing"

The type of a container is the specification after the double colon, not the loop structure/syntax.

Trying desperately to make lots of types orthogonally, even though their types are different, is a standard trick to make a language easy for non-programmers. It tries to hide the typing. This is insane for a language as pascal.

Show quoted text 6 lines
> IMHO this time to find arguments to justify something stupid as for..each You are right in these aspects; I'm not the person who cares much about that "foreach" either. That means that I can happily live without it and don't care about this syntax which is lacking usefulness, so I accept and actually agree to this decision in the end.

Good. I also don't exclude anything in the future, but

1) as discussed there is no pressing reason because it is so useful to implement it\
2) there is to my knowledge zero existing codebase that uses it.
3) .NET compability is no reason.

However e.g. in the unlikely event that a massive userbase would exchange their D6/D7 for D2005, we might eventually have to.

Pretty much the same story as dynamic array. At a certain point, the workarounds don't outweigh the aversion anymore.

Reply by email