There's a Delphi 12.1 patch and no-one told me!
2024-09-19 20:09 12_1_patch [permalink]
Well, "Wok" did actually, thank you "Wok". But I didn't notice it on the several Delphi-themed RSS feeds I have on my reader! But then again, I'm always incredibly behind on unread items, since I've already got about 600 feeds...
Clean Code: Big Chunks of Code
2024-08-15 11:35 ccbcc [permalink]
→ Understanding Clean Code: Functions ⚡
Sorry, but I strongly disagree. If you write a function and have it be called exactly only once, I dare to doubt the reason of existence of said function. I consider the call itself to be in the way. (Even if it's only because of the stack frame in memory and the extra line in the stack trace.) You may be better of with a raw file include (ugly!) or having the function be inline;
. What I typically do is have a big block of comment above and below such a section with explanation what it does and what its relation to sections above and below is. (Using {$region}
comes in handy here, as they are collapsed by default and may also provide 'overview readability' like the list of calls in the article, but without the code itself living somehwere else...)
It looks like good advice to split code in a series of calls, it looks like you're able to read from the list of names of functions that are called in sequence what is going on, but experience teaches this typically goes on an evolution of its own in the further progression of the project, and never sits quite right, causing more trouble than avoiding any. Especially when the functions themselves grow to do more things than their initial description.
What I usually do spend personal discipline on is making sure that the sections are independent among eachother, except for a limited set of references to objects that are operated on, and listed as such in the preceding comment. This is something that would get enforced by splitting in separate functions, but something that should emerge if you already think criticaly about the construction of larger chunks of code. Newer Delphi versions introduced the option to have a var
section in a begin end;
block, which could help with this, but I haven't grown accustomed to this yet. (Partly because I still keep a number of project fit to build with Delphi 7, sorry. The difference in file size of exe's and dll's is just too big.)
One more thing: In most cases, when I have sequences of code (sometimes tens of lines), that have to happen in sequence for a big operation (that sometimes get to hundreds of lines), each section get's its own try finally
and/or try except
, so you clearly know where something happens when something (inevitably) goes wrong at run-time.
This is ofcourse specific to Delphi (Object Pascal) and your milage may vary with other programming languages and development environments. It goes to show that its heritage goes back to Pascal which was designed to be a (theoretical) developer's language, and goes further back than C and its extensive family of languages that were primarily designed to be an evolution over assembler just so to get code to be cross-platform* and thus eliminating specific assembler as much as possible. (*: "cross-platform" here is PDP-7, Burrouhgs, Cray and punch-card-crunching machines from IBM; though it came in handy in the new Windows/
2024-01-08 17:48 xxm510 [permalink]
A quick follow-up release. I've had more reports of xxmHttp*.exe being wrongly identified as a Trojan horse, so I did more work on the code around the LoadLibrary call. (A very big thank you to VirusTotal. But that still doesn't fully guarantee it won't get flagged again now or in the future.)The NT-service versions apparently were broken, so I had to fix that. (And found a few more optimizations along the way!) I've been test-running a few days now and all works smoothly again. So be sure to update in case you've also ran into problems, otherwise nothing functional changed compared to revision 500.
2024-01-05 23:43 txsvc [permalink]
tx "stand alone version" is now available as an NT-service, since I added the files for xxmConv for it. (If you're interested, it's called from here.)
The original tx "stand alone version" was intended as a show-case to see if tx could work for you (and/or your team?), so it would only bind to 'local loop addresses' ('127.0.0.1' for IPv4 and '::1' for IPv6, when available) for security.
But if you like it — and are not planning to do development on tx itself — this service version is what you need. You could install it on a server on the local network, so it's available to your entire team.
If you do want to tinker with tx itself, — it's an open source project after all — you're welcome to install xxm to host tx.xxl
you build from source. (Hmm, should add a file with the steps in detail how to do that...)
2023-09-16 21:59 re210 [permalink]
v2.1.0: I've added a HTTP library that can do GET and POST requests with data from inputs and to outputs. I also switched to .Net 7.0.
WinHttpWS.pas: connect to a websocket using winhttp.dll
2023-03-30 23:02 WinHttpWS [permalink]
I needed to fetch something from a WebSocket real quick, but the project didn't have anything like networking components included yet. So I decided a quick-and-easy-way to get to what I needed is using winhttp.dll... I share this hoping it may come in handy for anyone else...
2023-03-03 22:51 dirdiff646 [permalink]
→ DirDiff v2.0.5.646
There was a bug when diff-ing XML files. Incorrect characters were shown when (re-)indenting nested XML elements. I also upgraded the project to Delphi Community Edition version 10.4
Eszett: enter ß by typing Ctrl+Alt+S (AltGr+S)
2023-02-23 22:24 eszett [permalink]
When typing German on non-German keyboards, it's not entirely clear how to enter the "ß" character. There's charmap.exe and Win+"." but those are all pretty indirect.
Install eszett.exe to map the combination of Ctrl, Alt and "S" (or 'AltGr' if your keyboards has it, and "S") to enter a "ß" character.
(Source code available here)
2022-06-25 00:52 FreeAndNil [permalink]
→ Coding in Delphi and beyond: Delphi Debates: FreeAndNil
;TLDR: I agree.
I, for myself, have a pretty straight-forward rule to follow. In most cases 'lifetime management' of objects is pretty plain and normal: there's one single place in the code where an object comes into existence (the call to a constructor), and exactly one single place in the code where it is cleaned up. In that case there's no reason that I can think of to use anything else than the Free
method. Sometimes the constructor is called from another constructor, and you free from the partner destructor, in effect linking the lifetime of the object to this 'owner' object. Most other cases, you just need an instance of a class to do something with. It typically looks like this:
var
a:TThing;
begin
a:=TThing.Create;
try
//...
finally
a.Free;
end;
end;
Neat! One very (very) important thing to note here is that under no circumstance you're supposed to do anything with this object reference after that (other than assigning with a new constructor call etc.) Thanks to Delphi internals, you'll probably get an access violation, but you might just as well end up calling some code that has been put in the memory where the instance was, and has unintended consequences.
If, for any reason whatsoever, you need/want to write code that may or may not be assigned to a live instance of an object, you could and should use nil
. In the places in the code where it's not sure if there's an instance, be sure to check for a nil
value. Consider this snippet:
var
a:TThing;
begin
a:=nil;//counter warning
try
if //only in some cases
begin
a:=TThing.Create;
//...
end;
//...
if a<>nil then
begin
//use a for something
end;
//...
finally
if a<>nil then
begin
a.Free;
a:=nil;
end;
end;
end;
Seasoned Pascal-coders will have objections to this snippet, rightfully so, but the point I want to make that there's some extra steps taken here to 'keep it safe'. There's just this one thing that's not so easy to spot: a.Free;
could in theory throw an exception. If there's an except
clause below that, and it wants to get some data from a
, it won't work. a
isn't nil, but the constructor may have already taken down the object instance so far down it will no longer behave as expected. There's a way around that though, and you can see for yourself rightaway if you have a look for yourself at FreeAndNil
itself:
procedure FreeAndNil(var Obj);
var
Temp:TObject;
begin
Temp:=TObject(Obj);
Pointer(Obj):=nil;
Temp.Free;
end;
(There's some casting to/from pointer and TObject here, but that's to make sure it works in even the strangest cases. It basically sets the reference to nil
before calling Free
.) If you've seen that first without the context I described above, you might think 'what is going on here' or 'what is the fuss about'. So I hope I was able to bring some enlightenment. The best case would be if you've learnt nothing new here, and also agree with this rule:
If you have an abnormal object instance lifetime management situation and/or need to entertain instance references that may be nil
, use FreeAndNil
. In all other cases use plain Free
(and keep calls to constructors and destructors in perfect balance!)
2021-11-24 20:38 ildasm [permalink]
Hier is een gek ideetje: zou ik met ilasm.exe sneller dingen voor dotnet kunnen op basis van mijn eigen taal, dan dat ik me in de dingen rond CodeDom en Roslyn zou moeten inwerken? Stel, ik doe kleine dingetjes in C#, kijk met ildasm.exe hoe die IL er uit ziet en die doe ik na. Alleen, veel optimizing moet ik niet verwachten waarschijnlijk. Behalve /optimize
die blijkbaar wat instructies kan verkorten, en eventuele achter-de-feiten optimalisatie van de JIT. Maar misschien zou het genoeg zijn om de bootstrappen? En/of beter de rest te snappen eenmaal ik verder raak met het echte compilerwerk. (Of zou ik toch eerst nog eens LLVM proberen?) Ik was voorzichtig begonnen aan een 'Pascal code gen', maar daar komt meer bij kijken dan ik had kunnen denken. En dan doe ik dat al om uit de weg te blijven van register allocation...
Delphi 10: "Debug" has "Use debug .dcu's" on by default
2021-09-01 18:48 d10debugdcus [permalink]
Since the community edition, and since it includes the command line compiler, I've been persuaded to switch some hobby projects I was sticking to Delphi 7 for. I've enjoyed a few of the new features I've been missing on (Ctrl+Shift+F! F6!), but also have noticed a few strange quirks I'm not so content with. [WARNING: what follows is my own opinion, you have every right to disagree and it is not at all implied you're doing anything wrong by disagreeing] If you start a new project, you get a "Debug" and "Release" configuration in the project, but the "Debug" project has the "Use debug dcu's" option checked in the project options under Building > Delphi Compiler > Compiling > Debugging. I regret that because when you follow what code does using the debugger and pressing F7 repeatedly, and you're not using the debug .dcu's, you only get to see code from your project. Especially for beginners, I think it could be quite jarring to end up in the thick of VCL-code without a clear way how to get out of there. (Shift-F8? Sometimes but not always.) If you F7 on a TStringList's LoadFromFile, it shouldn't descend into that unless you really need to and know what you're searching for down there... But that's just my opinion. Another thing that struck me is that local variables don't get zeroed by the 64-bits compiler, but I'm not sure if there's a switch or setting that controls that?
Ask HN: What is the SQLite of nosql databases?
2021-06-13 10:33 hnsqlitejson [permalink]
→ Ask HN: What is the SQLite of nosql databases?
Though I'm very much in agreement with:
The SQLite of NoSQL is still SQLite: https://www.sqlite.org/json1.html
there are situations where you could just use a single JSON object to store everything?
If your JSON implementation of choice does it correctly, and I attempted to get this right in my implementation, looking up a key from the list of key-value-pair should use a method that wastes no time and gets you to the value you want as swiftly as possible, no matter how many keys you need on the first level.
Then again, if you decide to use SQLite, and really need almost nothing else, I've created this one...
Quick, write it down: just another CPU design idea
2021-05-05 23:57 cpuidea [permalink]
Ever since learning about the Mill architecture, and watching an excellent series of MIT 6.004 lectures by Chris Terman (I can't find them on Youtube any more! But there are newer versions of 6.004 online which probably are great as well.) and reading up on what's new about x64 and RISC-V and ARM, from time to time my mind wanders if you could go crazy and design yet another CPU design that does novel things with the umptillions of available transistors and not have the downsides of the currently popular CPU's.
So here's an idea I just need to write out of my system, and let you have a look so you can see if there's anything there at all. Modern CPU's use virtual registers to have hyperthreading and speculative execution, and push whatever ahead in the hope it was the right branch to make pipelining work better for the workload at hand. The Mill architecture would handle that a little different and fill the pipeline just with more concurrent threads and interleave those. (At least that's how I understood what would be going on.)
What if you design a CPU so that it also takes in a larger set of streams of instructions, also using a bank of virtual registers that get alotted to these streams, but also have hot memory just like the closest cache is, but use that for the stack. Ideally you could expect programs to keep the current stack-frame fit within one or a few kilobytes, and by having a larger number of streams you could avoid having to switch this stack along with all the rest on context changes (by the OS). Switching the stack and overflowing the stack to and from memory is something that will have to happen, so you'll have decent support for that, but if you're after speed you'll try to avoid it as much as possible.
Let's have some numbers just to get a clearer mental picture. Let's say a core has support for 256 streams of instructions. If the work for them is pipe-lines across the rest of the core, addressing them would take 8 bits, so you would see a band of 8 lines pipe-lined to everything everywhere. It's not even required to have 256 instruction decoders, and sub-groups of streams could share commen instruction decoders, but depending on the instruction set design itself, this could turn out to be the bottleneck, but let's find that out with further design and research.
Let's say each stream gets 4KiB of hot stack memory, in total is 1MiB which is not unrealistic to have in a modern code nowadays, if I understood that correctly. This special memory could have extra lines so it automatically flows over into system's memory if the local stack index rolls over, which perhaps could also help with loading and flushing stack data on context changes.
With instruction fetching, stack handling and these streams doing their thing with alotted virtual registers, there's a lot covered, but the ofcourse the sweet magic happens in ALU's and related things, so down the pipe-line, according to what instruction decoding prescribes, the streams queue up to get one of the available ALU's to handle an operation.
This would be a point at which you start on a real design in a simulator, but that's where my knowledge is stronger than my experience. I just decide to start writing things down (right here, right now), let it simmer a bit and maybe pickup starting a first attempt sometime later. If you see what a former attempt like plasm ("play assembler") looks, don't get your hopes up too much. For now it's good that I wrote the core idea down here. If I ever get down to it again and get something working, you'll read it here. Sometime later.
Do n.GetFirstChild=nil instead of n.Count=0
2021-03-21 17:25 nodecount0 [permalink]
I wish I knew this one sooner! If you've worked with TTreeView before, and know about TTreeNode's HasChildren value, you need to check with OnExpanding, if you need to load the children or not. So I would typically have something like this:
if Node.HasChildren and (Node.Count=0) then //load children nodes
Only now after all these years I happen to come past this in the Vcl.ComCtrls.pas unit:
function TTreeNode.GetCount: Integer;
var
Node: TTreeNode;
begin
Result := 0;
Node := GetFirstChild;
while Node <> nil do
begin
Inc(Result);
Node := Node.GetNextChild(Node);
end;
end;
So I've been throwing away performance all this time! Because my 'are the children loaded yet' check was taking more time if they were and there were a lot of them, expanding nodes was slower. And I never noticed!
So it's a good thing I know this, and now I can just write:
if Node.HasChildren and (Node.GetFirstChild=nil) then //load children
205B random strings and no 'Delphi'
2021-02-28 18:48 randomdelphi [permalink]
→ Delphi-PRAXiS: Can Delphi randomize string 'Delphi'?
Ah, that takes me back. A while ago at work I got someone baffled by this statement: It is said that a thousand monkeys banging away on keyboards could at some moment in infinite time produce the complete work of Shakespeare (and that the combined internet forums are a living counter-proof). Now if you search online you can find an XML download of the combined works of Shakespeare, so it's not hard to find the relative occurance of each letter of the alphabet. One can guess this will have rougly the same values per letter as the total of the English language. So, then, if you take 'random' by its definition, and the monkey's produce text at 1/26 probability for each letter in the alphabet, therefore they'll never reach a point in time where they (re)produce the works Shakespeare.
Now, I'm not a real philosopher, or a statistician, so my thesis could be complete fiction and based on nothing, but sometimes you really got to take a lesson from practice. In theory, in infinite time, it's ofcourse possible that something really really inherently possible could emerge out of a random system, but there are characteristigs to anything random, and there are exponential things at play that soon but experimantal set-ups like with the link above, that they probably would produce the expected outcome in a time-span that exceeds the number of years we've got left before the sun sheds its outer layers and devours the earth, complete with a set of silicon-based machines churning away at putting a series of random characters in sequence and comparing them of some neat stories of a long gone English playwright.
2021-02-25 20:12 diytotp [permalink]
Recently, I've got a few things asking to enable two-factor-authentication, and I started using the Google Authenticator app.
I kind of like it. It's a simple enough app, there's a shared secret involved, but it gets pretty close to being airgapped and perfectly forward secure and all of those things. So I got thinking... What would it take to start using it for myself, in those little software things I create now and then...
Is there black magic or stick whittling involved? Nah, a little searching around, and it all appears to be cleanly described in RFC's 6287 and 4226... There has to be a warning here about not rolling your own crypto, but the world of hashing and encrypting really is interesting! I did SHA1 and HMAC before, and Unix' time apparently is UTC... So all you need* is the correct format of URL to put into a QR-code to load up a new key in the app. Then you can use this code to generate the 'current' pass-code for the secret:
github.com/stijnsanders/tools/.../crypto/totp.pas
*: and apparently base32-encoding, HashUtils was missing that...
Lobsters on Delphi: the good and the bad
2021-02-18 00:20 lobsters [permalink]
→ Lobsters: 26 Years... of Delphi
Aaw, look at that, the good and the bad on a single page.
2020-12-18 16:26 invoicetemplates [permalink]
→ https://stackoverflow.com/questions/65348138/quickreport-on-delphi-sydney-10-4-1
Oh my, I didn't know. I guess we'll see this more and more with one-person open-source projects, that people stop with the project for all kinds of reasons.
But about reports, I've made this really elegant thing at work to script the design of a report with just a few basic commands (line, text, image, matrix, block, repeat...) that allows you to write what the report should look like, and make lots of small alterations later. If you really need your reports just right, I've always found a graphical designer to introduce minor artefacts that you sometimes need to work around...
I know there are tons of similar things out there, like TeX and PostScript, and even HTML or MetaFiles, but it was grown out of neccessity and suffered "dogfooding" from the very start, which shows in its design and execution. And thanks to SynPDF, (or "Print to PDF" for that matter) you can just exports PDF's with it as well. So I really should take some time and re-do it on my own time and open source it... If I can make it even better and cleaner, I might introduce the open-source version as a replacement at work! (... Oh-oh!) (... or was it this one?)
Could you do a mill architecture with RISC-V?
2020-09-29 22:26 millrisc [permalink]
I wondered today if it would be feasable to build a processing unit according to the mill architecture with the RISC-V instruction set. But as always, I also wonder if I'm out of my league and know far too little of these things to come even close to forming an accurate answer, or even if I'm anywhere close to a good idea. If I understood correctly, the mill architecture does what modern CPU's already do: use a bank of virtual registers with multiple heavily pipelined streams of translated instructions. CPU's that do hyperthreading have two streams of instructions, but that's about it. I'm really rooting for the first article I read about a real system that has more than two, but with just a little imagination, and if you know the 'price per transistor' keeps going down, you can image a huge bank of virtual registers, with a bank of ALU's close, that processes a 'large' number of instruction streams. Ideally even a totally variant number of instruction streams. This may be a caching nightmare, but instead of wasting a lot of in-system logic to do branch prediction and other bookkeepingof what an instruction stream is doing, what if you could just load another instruction stream, just up until you get all of the piplined stages fully occupied...
Alas, I'm so much out of that business that I guess I need to conclude I'm a wild dreamer. I may stumble on a good idea now and then, but know too little to be sure. So I'll note it down here. I hope I haven't bored you, and with just a little luck, you are able to judge about this idea. If so let me know...
2020-09-23 10:31 meanbad [permalink]
→ MEAN Stack Considered Harmful
An important read, also reminds me of what I've written here.
Carefull with Gogole Sheet CSV export
2020-06-26 14:18 ggggrgviz [permalink]
Ready for another story from the trenches? So image a Google Sheet made by someone else, with all kinds of dat in about 30 columns, of about a few thousand rows. Yes, it's a stretch to keep using Sheets for that, but this data will serve for the analysis for a decent application to manage this with... That probably won't be my team handling that project, but I had to do a quick cross reference of this data with the data in the database of one our current projects. The best way to do cross-checks is get the sheet into a table in the database to run queries. I guess you should be able to import a CSV pretty easily, right? I searched around and found this:
https://docs.google.com/spreadsheets/d/{key}/gviz/tq?tqx=out:csv&sheet={sheet_name}
Which I thought would provide the data in just the way ready for me to import. Wrong. The second column just happened to have codes for all of the items that are numeric for the first few hundreds of items, and then alphanumeric codes. At first I thought the CSV importer was fouling up, but I hadn't looked at the CSV data itself. Turns out this CSV exporter checks the first few lines (or perhaps even only the first one!), guesses the column is numeric, and then just exports an empty value for all non-numeric values in that column!
The code in that column was only in a number of cases needed to uniquely identify the items, so I first was looking for a reason why my cross-match was throwing duplicates in all of the wrong places. Ofcourse. Weep one tear for the time lost, then move on. Take solace in the wisdom gained.
I solved it by using the CSV from the Export menu. I only needed it once so I didn't get a URL for that.
2020-06-05 17:23 cppwebdev [permalink]
→ Quora: Why is C++ not used in web development?
For what it's worth, in creating xxm it feels like I'm trying to create this exact thing except for with the Object Pascal language. Yes, you can do HTTP all by yourself, you can do an ISAPI extension DLL or a Apache httpd module, but you'll still get a strange hybrid between a server service and a web application that has nothing like a platform you can depend on to do the heavy lifting. And, if I'm permitted to speak frankly, in C++ this would be ugly! And probably would need a lot of code to make even the basic things happen. Too bad (Object) Pascal has been called verbose, if you know what you're doing you can write the logic you need in concise readable syntax.
Still what I'm finding in trying to get people to take a look at xxm, they either are unable to disregard the visual RAD form-designer style programming like I do, and don't get that xxm in it's current for is much more like early-days PHP but with the Delphi compiler instead of the script interpreter server-side; or they are fixed in thinking 'the web + Delphi' is all about a data-layer, doomed to only serve plain CRUD requests to and from a front-end layer, and never talk to the user's browser directly. Please! A big strong no on both accounts. Let me explain.
I've always seen — pretty much since FrontPage and DreamWeaver — that if you have a visual designer to manage what to go on a HTML page, you get really ugly code. It'll look the way you want, but a lot of decisions have been made for you. Some with negative consequences for you down the road. And the underlying code is strange and ugly, unneccessarily complex for your website-visitors' browser to work with. I guess modern front-end web-devs must have known this also as I've seen a regression towards working on big chunks of raw coding the last decade. Yes, font-ends are hacking away in CSS and HTML, and not with their bare hands, all kinds of CSS pro-processors and template engines do the heavy lifting behind. So if you know what you're doing, you can have this as well, in a Delphi project. I don't need a form designer, I make the page-builder first with dummy data, and run it in the browser. Don't forget, hitting F5 in the browser to an xxm website running over a development-handler, fires up the Delphi compiler there and then. Edit→Save→Refresh→Repeat
Then there's the other thing. If you start a conversation about webservers and Delphi, bam there's DataSnap. Strange. Is it because I'm strongly dys-convinced about ORM's? (Reminder to self: still have to write that grand essay about what's bad about ORM's.) Yeah sure, if you have things that use RTTI to serialize your data-objects in some way, you can easily use one of the available options to serve it over some web-server and bam you can call it REST and get away with it. But this is a completely different thing than having a full blown web-application serve from something you created! Complete with images and stylesheets. And yes you can have both🤯 from the same web-server-service🤯. I've had people walk away, unable to believe me. It still feels like it's a case of opening your mind to be able to see it.
Anyway, sorry about the rant. I'm getting tired of trying to find the people that combine real web dev with Delphi for the server side. Yes there are a lot of new things that compile (Object) Pascal to JavaScript, but that's another story. That's nice for the front-end. But if you dig deeper, or want to reach the people that you can't offload your gargantuan client-side workhorse to, please think about xxm. Give it a try, see if you can make it work. If you want an example of what I'm talking about, take a look at feeder or tx.
2020-05-27 10:30 primescheck [permalink]
→ J: Doc/Articles/Play104: The 10,000,000,000th Prime Number
http://yoy.be/home/primes/?a=2&x=10000000000&t=1&n=1 p(455052511)=10000000019 is actually the first prime past 10^10, but that does mean my primes thingy found the 455052511 primes lower than that.
http://yoy.be/home/primes/?a=1&x=10000000000&t=1&n=1 p(10000000000)=252097800629
2020-03-16 20:29 nottx [permalink]
→ Microsoft Teams goes down just as Europe logs on to work remotely — Verge
Tx wasn't down, especially the instance you host yourself.
About x in ['0'..'9'] and CharInSet
2019-11-05 22:42 anticharinset [permalink]
I'm still in the (slow) process of letting go of Delphi 7 and embracing the modern version(s) of Delphi, which to be honest was only possible since there's a community edition (that includes the stand-alone compiler(s)). I was in doubt if I would move over to the WideChar
based default string
, but since Windows internally switched long ago — and you get emoji-support for free — I thought I should switch also and haven't even tried to override the new default and switch string
to be AnsiString
just to keep things the old way. It works remarkably well. Any code that assumes the length of the string is also the number of bytes to move around needs to change, but that's a good opportunity to change them over to operations that use encoding support. With PChar
and char
that also changes mapping (to PWideChar
and WideChar
respectively) any coding use those just keeps working. Except in code like x in ['0'..'9']
which I apparently use a lot. It works except when compiling it throws this warning:
Warning: W1050 WideChar reduced to byte char in set expressions. Consider using 'CharInSet' function in 'SysUtils' unit.
At first I was baffled. Why is it reduced to a byte char? I know set expressions trigger all kinds of compiler optimizations (that's why I like to use them so much), but has someone been too lazy to make them happen with 16-bit values as well? I guess we're talking assembler jump-lists here, so it probably matters if you can limit them to 256 positions, and 65536 positions would add too much of dead chunks of data into your compiled code... But still. x
is WideChar
, any '0'
-style literals should default to WideChar
, shouldn't they? So I regret there was no preference to support code re-use here, and CharInSet which appears to be just a wrapper around the in
syntax, strange.
I don't like warnings and hints. I typically avoid them at all cost, treating them as compile errors. It helps to keep your code clean, and avoids trouble down the line. (But if you're really into avoiding trouble down the line, you should do decent static code analysis...) I'm kind of strict on myself that way. So I need to know what's the best way to avoid this warning. In someone else's code I saw x in [WideChar('A')..WideChar('Z')]
but that doesn't appear to suppress this warning. So I settled on AnsiChar(x) in ['0'..'9','A'..'F']
which probably calls a Unicode conversion routine, but I don't care enough. Old Delphi understands it, new Delphi no longer throws an error, and as far as I know the compiler optimizations still kick in and I haven't seen any performance loss over code like this. So I can sleep again.
Unless someone throws me a much better alternative and I won't sleep for a week because it feels like I should have known that all along...