Is there a way in FPC to declare a field in a record that takes no space and is there only to provide a way to reference that location in the record ?No. The "static" part should become the record. The flexible part should be read separately.
No. The "static" part should become the record. The flexible part should be read separately.Thank you. I wanted to make sure I didn't know of some FPC feature that would allow an equivalent/parallel construction.
You can however, declare an additional structure that would cover for "flexible array member".yes, that sounds right. It works using "absolute" to overlay the full struct over the "truncated" struct. I tried a typecast and FPC complained about it being an invalid typecast (absolute works, that's good enough.)as a result you can access "c" array using mystruct_full, BUT...
mystruct = packed record a,b: DWORD; end; mystruct_full = packed record hdr : mystruct; c : array[byte] of DWORD; end;
also, sizeof(mystruct_full) would obviously be greater than sizeof(mystruct)Yes, there are some "details" that one must be careful with (such as size)
While sizeof(mystruct) between C and Pascal would match in this case.
I find it unpleasant to have to define two records to achieve the same result of one structure in C. Not to mention the possibility of using the wrong size.Yes, excellent idea. The property "c" in Pascal becomes the offset marker "c" in the C struct. That is really good. :)
I would use:
program Project1; {$mode objfpc}{$H+} {$ModeSwitch advancedrecords} Type mystruct = packed record private function Getc(i: integer): DWORD; inline; public a,b: DWORD; property c[i: integer]: DWORD read Getc; end; function mystruct.Getc(i: integer): DWORD; begin Result := PDWORD(@self.b)[1+i]; // or PDWORD(sizeOf(self)+pbyte(@self))[i] or ...etc; end; var a: array[0..5] of DWord = (0,1,2,3,4,5); sample: mystruct absolute a; begin WriteLn('Size: ', SizeOf(mystruct)); WriteLn('a: ', sample.a); WriteLn('b: ', sample.b); WriteLn('c[0]: ', sample.c[0]); WriteLn('c[1]: ', sample.c[1]); WriteLn('c[2]: ', sample.c[2]); WriteLn('c[3]: ', sample.c[3]); ReadLn; end.
As you can see, c does not occupy any memory.
And if you are bothered by the verbosity of the previous Pascal property, and don't mind seeing pointers (I am sure you don't):I like this one even better :)
mystruct = packed record a,b: DWORD; function c: PDWORD; inline; end; function mystruct.c: PDWORD; begin Result := PDWORD(pbyte(@self.b)+sizeOf(self.b)); end;
of course, you can still access "c" as an open array to read/write its values:
sample.c[i] := i+1
This is what we call a "buffer overrun".Not if the memory backing the record is intentionally large enough (of course you shouldn't use it as a stack variable, but only as a pointer). Such constructs are often encountered when dealing with C code (see the other thread where this was talked about).
Ever wondered why almost all lessons about "Things you shouldn't do while programming" are about C++? Because most of the things they tell you not to do are C++ specific. You cannot do them wrong in most other programming languages.note: flexible array member feature is not inherited in C++. It's C only feature.
Many users from other languages found Pascal is great and they want to use it seriously. But they already have written many codes in their previous language. If they can't port their old codes to Pascal, it may become a barrier for them to use Pascal.Exactly!. Thank you for stating the obvious which seems to be not quite obvious to some.
I read the thread and saw many suggestions for this issue. Sorry, but it looks ugly to me. I love the simple and clean syntax of Pascal.Pascal's clean syntax is one of its nicest features. There is usually a clean/Pascal way of implementing a feature found in another language. A little pondering usually helps get there. What's important is the desire and dedication to implement it nicely, that's what will make a difference.
But think the other side, if Pascal can be easily to port from other languages, it will be a great advantage.Not only a great advantage for the Pascal language but, also for those who use it.
If you really want to program in Pascal like in C, use pointers. Don't rape the language.Not only is that rather dramatic and over the top, the construction "<vartype> <array[]>" is in C, precisely to be able to obtain a pointer to the desired location within the struct without having to declare a space-consuming field to obtain it.
C and C++ also have lots of exceptions for many things. But it was popular because it was short and cryptic. It looked like a magic formula, for the uninitiated. Very macho.I believe there is some [added word] truth to that but, the reason some people use C is because, whether cryptically or cleanly, there is usually a way to tell the compiler what you want and the compiler will usually generate decent code for it. That is a _big_ advantage. In the case of Windows specifically, the API is spec-ed in C. That means that, so far, the only way to get access to the full API definition is by using C/C++. Sometimes just that is enough to use C/C++ instead of Pascal/FPC. When one is writing a program, the objective is to write the program, not to have to translate function headers and structs from C to Pascal - which in most cases is fairly quick but sometimes the Pascal translation is something that had to be shoe-horned because the language lacks some type description facilities.
The two things C and C++ have inherited form this, are a fascination with speed and that it is really easy to fuck up. It's much harder to do it right.There is definitely some truth to that but, it's got its pros and cons. A well optimized program that is snappy is often a pleasure to use (provided it's not riddled with bugs as a result of some ill-conceived optimizations.)
Correctness is not a requirement of the language.You're right. Correctness is a requirement of the _programmer_. That said, it is true that C offers a very limited amount of help in that area. That's one of the areas they _greatly_ improved in C++. Type checking in C++ is at least as good as in Pascal.
And you guys want to add the worst things from C to Pascal, simply because C can do that. You want less restrictions, because it allows macho programming. And make it much easier to fuck up.Not only that isn't the case, it is completely over the top. Adding simple things like a zero-size field to use as a reference in a struct/record is not unclean in any way. On the contrary, having that results in code that is much cleaner than the un-intuitive pointer manipulation you have to do when the feature is not available.
While C and C++ (especially Microsoft and LLVM) try to make C and C++ much, much stricter, to prevent all that. They would rip all that out in an instant, if it wasn't for backward compatibility.They are making it stricter for the compiler to be able to flag potential programming errors but, they are _not_ restricting what the compiler can do. On the contrary, constructs such as "array[]" are fairly new and they are a much cleaner way to provide an address to access the field than using "array[ANYSIZE]".
It would be nice if FPC supported the "array[]" construction.in what sense?
In pascal arrays are always of the known size. (you can always run length() on an array)Not really. In a dynamic array declaration, the dynamic array is a pointer to an array of unknown size. The size is only known after using SetLength().
In this sort of C-style declaration, the length is never known.Correct. The purpose is simply to mark the start of the array. It's very similar to a dynamic array declaration, the only difference is that in a dynamic array declaration space is reserved to hold a pointer to the array. In a construct such as "array[]" the compiler would have the address of the array as an offset into the record just as it does for any other field.
If we want them to use Pascal, we have to make sure that they can continue programming as they did and reuse all their old code.No. (more later)
Know Lisp? There's an endless amount of things you can do in Lisp, that youYou're comparing Ducks, Tricycles and Bushels of oranges. The functional purpose of those languages differ greatly. Pascal isn't JavaScript and was not designed to do what JavaScript does.
cannot do in Pascal. Ok, it's not that popular anymore.
JavaScript. Very popular. Classes are the same as (anonymous) functions, and they're stored as text (or as p-code). Like with .NET WCF. Eval() can do lots of things that are impossible in Pascal.
C and C++ are some of the worst languages, but they're used most. So you should be able to program in Pascal just as you did in C and C++, and reuse all your old code.But the fallacy you've built is that there is no purpose similarity between Pascal and C/C++. Unlike with JavaScript, there is plenty and, whatever - desirable - features are present in C/C++ could be added to Pascal (often requiring some cleanup in the process.)
Why? If you want to program in C or C++, program in C or C++! Not Hard!Here is another thing that's not hard. If you want to program in a better language than C/C++, program in Pascal and slowly add to the Pascal language the useful features found in C/C++ removing the many "warts" in the process.
If you want to use a programming language that protects you against 90% of the pitfalls of those languages, while still offering the same possibilities, use Object Pascal.Good line for a commercial but, if you want to write a capable operating system, use C.
Not really. In a dynamic array declaration, the dynamic array is a pointer to an array of unknown size. The size is only known after using SetLength().dynamic arrays are managed types. Thus would be set to nil with zero size.
440bx, did you watch the video I linked? I'm pretty sure you'll totally agree. I leave it open if I do ;)What link are you referring to ? ... maybe I missed it but, I don't see a link anywhere.
In Pascal the size of array is (must be) always known.I used the dynamic arrays as an example because it has similarities with "array[]". There is no reason for the size of an array to always be known and even now, in FPC, there are arrays of unknown size, specifically, any typed pointer can be used as an array reference. FPC already sees pointers the same way as C, as the address of an array.
I like both methods of coding but when it comes to managing multiple items of the same thing you can notNope. I think the only thing that might not beat OOP is honest-to-goodness totally out of control, full blown, spaghetti code. That _might_ be worse.
beat OOP.
I've done the way of creating multiple forms without OOP and it gets to be a mess!I believe you. That's usually what people who don't know how to do it end up creating.
That video is absolute garbage..Your reaction is quite typical unfortunately. He makes quite a few good points. He also missed quite a few of them but, he is much more often right than wrong.
This one: https://www.youtube.com/watch?v=QM1iUe6IofM (https://www.youtube.com/watch?v=QM1iUe6IofM)
I used the dynamic arrays as an example because it has similarities with "array[]". There is no reason for the size of an array to always be known and even now, in FPC, there are arrays of unknown size, specifically, any typed pointer can be used as an array reference.There are three reasons on top of my head, why the size of an array always have to be known:
FPC already sees pointers the same way as C, as the address of an array.you're right. Both treat pointers identically.
A tiny bit faster:
mystruct = packed record a,b: DWORD; function c: PDWORD; inline; end; function mystruct.c: PDWORD; begin Result := PDWORD(pbyte(@self.b)+sizeOf(self.b)); end;
There are three reasons on top of my head, why the size of an array always have to be known:Here are my thoughts on that:
1) length() - has to return something. The function has to run on anything declared as an array and must return something
2) rangechecks - which are applicable to anything declared as an array.
3) passing an array to another routine (as an open array)
So, while there are syntax similarities, the semantic is different.
Arrays in both C and FPC are pointers (and any language that supports calculating an address based on an element's size.) The operations allowed differ based on how those pointers are declared, which can be as a pointer with a range (e.g, array[low..high] of something, commonly thought of as an array) and a pointer without a range (p : pchar; just a pointer.)FPC already sees pointers the same way as C, as the address of an array.you're right. Both treat pointers identically.
But what you're referring to is pointer math, not arrays.
Arrays in C are pretty much pointers. Arrays in Pascal are arrays (with a range, meaning the size is known).
The Pascal language itself still allows you to get C-like behavior (as shown multiple times on the page 1)
but doesn't do that automatically in any manner (by not providing a similar functionality of an array of unknown size)
Faster or not, that is very clean. Very nice, thank you!.
mystruct = packed record a,b: DWORD; function c: PDWORD; inline; strict private cStart: record end; end; function mystruct.c: PDWORD; begin Result := PDWORD(@cStart); end;
Here are my thoughts on that:in that case you don't have an array. Or an array is always of a zero size.
1) ...
2) ...
3) ...
The distinction between a pointer and an array is really artificial.in your case you should really stick to the plain typed-pointer type, rather than array[] of any sort.
100
200
No, it is not useless. It is quite a simple and useful way of marking the start of an array in a variable size record. The array can be populated just like any array. If a programmer tells the compilerHere are my thoughts on that:in that case you don't have an array. Or an array is always of a zero size.
1) ...
2) ...
3) ...
Which makes it pretty useless.
This one: https://www.youtube.com/watch?v=QM1iUe6IofM (https://www.youtube.com/watch?v=QM1iUe6IofM)
That was 45 minutes of my life I will never get back.That's funny. It doesn't matter how you spend any minutes of your life, you'll never get them back no matter how you spent them.
But OOP simplifies many problems, if I have 10 plots to draw that share 80% of the codebase, that is a no brainer.There are lots of bad programming practices that simplify things, for instance, global variables but, it doesn't mean they are good. The thing they all have in common is that the cost of the simplicity they bring is paid in complexity in another area but, if one chooses to ignore their cost then, they are great.
Thanks, I'm glad you appreciated my joke.That was 45 minutes of my life I will never get back.That's funny. It doesn't matter how you spend any minutes of your life, you'll never get them back no matter how you spent them.
Everyone is free to avoid OOP and use old school FORTRAN, C, Pascal, etc. I find it useful though.But OOP simplifies many problems, if I have 10 plots to draw that share 80% of the codebase, that is a no brainer.There are lots of bad programming practices that simplify things, for instance, global variables but, it doesn't mean they are good. The thing they all have in common is that the cost of the simplicity they bring is paid in complexity in another area but, if one chooses to ignore their cost then, they are great.
The guy in that video is right but, no one is going to listen. He might as well be talking to a wall.
You just have to know how to use it.That's what OOP programmers tell themselves to feel good. Those who realize how bad that thing is just don't know anything, it's so much easier that way.
That video is absolute garbage..Your reaction is quite typical unfortunately. He makes quite a few good points. He also missed quite a few of them but, he is much more often right than wrong.
What I want to ask is:
Can anyone write me a simple code of GUI or TUI module without using OOP?
So I can learn from the code and rewrite my glGUI without using OOP. By experience it myself I can understand how good or bad OOP is.
I'm sure writing GUI module without using OOP is possible but I believe it should be very hard. Please prove me wrong.
I often hear some said OOP is bad. But their explanations are out of my ability to understand. My glGUI progress is slow because I have limited time for working on it. I am neutral, I'm not a OOP fanatic but I can't write GUI without using OOP.
What I want to ask is:
Can anyone write me a simple code of GUI or TUI module without using OOP?
So I can learn from the code and rewrite my glGUI without using OOP. By experience it myself I can understand how good or bad OOP is.
I'm sure writing GUI module without using OOP is possible but I believe it should be very hard. Please prove me wrong.
It would be nice if Fpc had a C:Array[] of Dword; so that it can generate a location without an instance.No. This feature would only have a rather restricted use (namely as the last field of records) and as others demonstrated there are solutions that make use of existing language features to provide the same result. They might involve a bit more typing, but they work now.
It would be nice if Fpc had a C:Array[] of Dword; so that it can generate a location without an instance.No. This feature would only have a rather restricted use (namely as the last field of records) and as others demonstrated there are solutions that make use of existing language features to provide the same result. They might involve a bit more typing, but they work now.
I've seen some undocumented use of an Empty Record which is fine but it still needs a type cast over it
to take advantage of it and maybe helper functions. Still way too much code and very unreadable afterwards.
The lot of you may not like the C approach but this I can tell you, its a lot cleaner and simpler to understand over what hacks, if workable, that are offered here.Those are good points and I share your viewpoint (which, just like yours, isn't worth anything) but.... the reality is and will very likely continue to be :
There are some things in C that are clearly laid out no matter how old they are. Other languages do not need to copy the syntax but they should be able to offer a straight solution to it.
So I've seen here so far, over lapping Records which requires more work to implement and less readable.
No. This feature would only have a rather restricted use (namely as the last field of records) and as others demonstrated there are solutions that make use of existing language features to provide the same result. They might involve a bit more typing, but they work now.Making something simpler, cleaner, easier to read and understand is not what drives the inclusion of a feature in FPC. It gives the impression that the people who are responsible for updating the C standard are just producing useless things no one needs.
My two pence.
I believe this is pretty good selfdocumenting.
Of course it would be nicer, if this could be written inline as property. (I love properties ::) )
program Project1; {$mode objfpc}{$H+} {$modeswitch advancedrecords} type mystruct = packed record a,b: DWORD; function c: PDWORD; inline; // return adress after record end; function mystruct.c: PDWORD; begin {$T+} // @ now gives typed pointers c := PDWORD(@self+1); end;
A tiny bit faster:Thank you. I expected both to have the same assembly, but it seems there is an issue with constant folding in FPC 3.0.4?
mystruct = packed record a,b: DWORD; function c: PDWORD; inline; strict private cStart: record end; end; function mystruct.c: PDWORD; begin Result := PDWORD(@cStart); end;
So I guess the juror have tallied their votes.
There is a [better? easier?] way to get new features added to FPC. If you can get them added to Delphi.
I want to thank all those who contributed some way of implementing that C construct.
Someone please document it on the wiki page. It can be valuable for new users coming from C.No way, we do not want them here. >:D
That should resolve to an address.Every time you touch MyRecord.C[ beautify it with:
Untested;
{$R-} @MyRecord.C[0];
ah, but you can with what I used originally..
TMyRecord = record A:DWord; Case Integer of 0:(B:DWord); 1:(C:Array[-1..-1] of DWord; End;
That should resolve to an address.
Untested;
{$R-} @MyRecord.C[0];
I need to find some Delphi devs and hint them on..... >:DHitting two stones with one bird. >:D
I need to find some Delphi devs and hint them on..... >:DI am not fond of being pessimistic but, it's rather unlikely to make a difference. The result will most likely be along the lines of what you observed in this thread of yours https://forum.lazarus.freepascal.org/index.php/topic,43898.msg308122.html#msg308122 (https://forum.lazarus.freepascal.org/index.php/topic,43898.msg308122.html#msg308122)
Hitting two stones with one bird. >:DLOL... that either requires a large bird or the stones to be close together (or both!)
Someone please document it on the wiki page. It can be valuable for new users coming from C.https://wiki.freepascal.org/Flexible_Array_Member
https://wiki.freepascal.org/Flexible_Array_MemberNicely done.
using that style of coding here's my HACK!,,. still.There is no need for an additional setter. Assuming the record is declared like this (as mentioned in some posts already):
TmyRecord = Packed Record A,B:DWord; Function C(Index:Integer):DWord; inline; Procedure C(Index:Integer;AValue:DWord); inline; End; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } Procedure TMyRecord.C(Index:Integer; AValue:DWord); begin PWord(SizeOf(Self)+UintPtr(@Self))[Index] := AValue; end; Function TMyrecord.C(Index:Integer):DWord; Begin Result := PWord(SizeOf(Self)+UIntPtr(@Self))[index]; End; procedure TForm1.FormCreate(Sender: TObject); Var T:TmyRecord; A:Dword; M:Pointer; begin M := GetMem(1000); TMyRecord(M^).C(1,100); A := TmyRecord(M^).C(1); Caption := A.ToString; Freemem(M); end;
All this work to make buggy and unmaintainable code. %)You mean C of course, I presume? :o ;D
from C perspective this actually making a less buggy code as the offset calculation is now compiler's responsibility.All this work to make buggy and unmaintainable code. %)You mean C of course, I presume? :o ;D
from C perspective this actually making a less buggy code as the offset calculation is now compiler's responsibility.
Only if you don't have to do any bounds checking. (IOW are absolutely sure that the range of elements you check are actually in the buffer.Not using flexible array member still requires doing the same bounds checks.
...
All this work to make buggy and unmaintainable code. %)Again, this is required when one wants to conveniently interface with external libaries (e.g. WinAPI), especially if one does not want to deviate from the original record (or the documentation in case of MSDN) too much.
But I almost always make my own Pascal-like strings, even on microcontrollers, as I hate the C ones. They would be easy to convert.
it would like PASCAL like if they would simply allow a sizeless field...
There you have a field with size 0. And now?This is code extract from my revisited heaptrc unit, specifically representing the structures involved in heap memory allocation :