Jump to content

David Schwartz

Members
  • Content Count

    1180
  • Joined

  • Last visited

  • Days Won

    24

Everything posted by David Schwartz

  1. David Schwartz

    How many people use Delphi?

    As far as performance goes, I don't think I've ever worked on a Delphi project where the speed of the code was ever an issue. I've seen planty of situations where we got complaints about performance, and in every instance they were tracked down to poorly-devised DB (usually SQL) queries. I've also seen some poorly written code that sped up amazingly with a little bit of refactoring. But none of it was slow because of compiler optimizations -- or lack thereof. Shoot, most projects don't even bother to turn off Debugging code support! UIs offer plenty of time to get stuff done while the user is waiting for back-end queries to process. One place I worked at for a while involved insurance "illustration" apps. They cared far more about repeatable math results with predictable rounding errors than in how fast the calculations ran. When you can be held legally liable for calculations that have slight rounding errors that get magnified over 40-60 years, that's a problem. A really BIG and EXPENSIVE problem. I've worked on a bunch of real-time embedded software platforms, and they were all pre-Delphi. But they all used C and assembly language. They were always paranoid even to use C++ for years after it came out. They mostly avoided Windows as well. (Does anybody remember the fiasco when they were building the new Denver Airport using Windows NT? It was designed as a real-time embedded system and it just didn't work. They have miles of tunnels there for moving luggage that were simply abandoned because the idiots in charged believed Win NT was a Good Idea for controlling a distributed network of control nodes. The company whose DB they were using ended up being thrown under the bus and went out of business. They were using a Windows-based C compiler, that may have been Borland's.)
  2. David Schwartz

    How many people use Delphi?

    In the "Is Delphi Dead" category, one of the largest users of Delphi over time has been the US Veterans Administration. Delphi was used for all of their front-end apps, and MUMPS for all of their DB needs. (I worked for a company for a while that was working with them, and their "API" as it were was a bit of code published in 1996 and a threat that anybody who touched it in any way would be tarred-and-feathered. I know someone else who went to work with another very LARGE tech company that had just secured a big VA software contract, and he was hired to organize a team to do the Dephi part. Everything that goes on inside of VA hospitals and their facilities worldwide runs Delphi on their UIs. That's not to say that some companies haven't built simple Delphi adapter layers that allow them to run something on top of them, but Delphi was used to issue MUMPS DB requests and get back MUMPS-formatted responses. I've been out of that loop for several years now, but this is a prime example of a huge organization with a TON of Delphi code that wasn't going to be moving to anything else very soon or very quickly. And keep in mind that the VA is not just a "medical facility" -- besides HIPAA and related requirements, they treat symptoms and injuries caused by stuff that's highly classified by the US Government and I was told that HIPAA regs pale in comparison to the other secrets they have locked away in their DBs. "Security by obscurity" seems to work well for them. The US Government might well be keeping EMBT on life support simply to ensure it does NOT go belly-up. Keep in mind there are plenty of companies paying Microsoft to continue issuing security updates for Windows 7 to them, presumably to avoid that cost and "trauma" caused by being forced to move a bunch of code to a newer version of Windows that may cause their software to operate improperly. I've also worked on a couple of State Govt contracts that have 10-15 year-old apps written in Delphi that they are forced to update periodically as state laws impose changes in things the software manages. At one place, I was told the legislature there had been trying to pass a budget to replace all of the software and every time they did a formal analysis, it was always far cheaper to just pay to have contractors come in and fix the code than go through the hassle of replacing it with something totally new. The biggest threat to their software was not Delphi, but being forced to upgrade all of their hardware and Windows software that usually led to a lot of breakage that, of course, nobody ever budgets for.
  3. David Schwartz

    How many people use Delphi?

    Stack Overflow is not like most social media sites with a "newsfeed" that are more like sitting on the bank of a river watching things float by, many of which are the same Qs and As on different days. Delphi evolves very slowly, and a large number of users are still working with much older versions -- many even D7. There are a bunch of folks on SO who do their best to slap people who don't do searches (although it helps a lot to know what exactly to search for that may already be there, which is my biggest impediment). So in a nutshell, it may be fair to say that most of the questions people might have about Delphi have been asked and answered. SO is a rich resource in that respect. Newer languages and ones like C++ and C# are evolving much faster than Delphi, so of course there will always be lots of questions on newer features and updates. I don't know if those metrics on SO are measuring Delphi-related SEARCHES or just POSTED QUESTIONS. Regardless, with such a slow evolution of the language and the fact that it retains so much backward compatilbility, what stone hasn't already been unturned when it comes to, say D7?
  4. David Schwartz

    How many people use Delphi?

    I'd say that this is not a very meaningful question. There are still tons of companies running IBM 3050 (?) emulators on 360 emulators on newer systems because the software has been running and stable for decades and the source code was lost a long time ago. Delphi was really popular up until D7, when they made some changes that caused several popular component libraries to stop dead in their tracks, which is why D7 is still popular. The truth is, there are TONS of Delphi apps built in the D4-D7 time-frame that are still running today. I suspect a huge chunk of EMBT's revenues come from such companies who keep their licenses up-to-date just in case they need to hire some folks to fix things. Last place I worked, they had a team of 8 or so Delphi Devs who all quit at one point save two new guys, who were their for another decade. I was hired to replace one who had recently left, and while I was there the other one left. They hired a new guy and transitioned another fellow over from C# who didn't have much trouble learning Delphi, then cut me loose. That facility was on track to be generating $1.5 billion in revenues this year. The entire facility is driven by software written in Dephi between 2006 and 2010. Management there has been trying to replace the Delphi code since 2014, and has refused to allow it to be expanded or extended or anything. It's still their most stable, most reliabe and full-featured platform in the company, and they can't just shut it off without losing hundreds of millions of dollars of revenues. Delphi apps have become the platform companies love to hate -- they want to get rid of them, but they can't afford to. For a decade now, the Delphi code has supported features beyond what their other platforms don't offer, and apparently can't offer. And the Delphi version has not had any new features added in TEN YEARS while the others have been under active development the entire time! Go figure! (They have had 30 devs working on the other platforms, and only two have been maintaining the Delphi code since 2014.) Personally, it makes no sense to me. They've got a huge installed code base that's stable, reliable, and fully debugged. So why go with another platform where all of the code is new, will take a couple of years to get to where the Delphi version was three years earlier, and will be full of bugs for the next several years? Why not build the NEXT version in Dephi, re-use as much existing code as possible (reducing your programming needs to some extent) and save a huge amount on development costs? Like I said, Delphi is the platform that companies love to hate today.
  5. I've been asking ChatGPT (free version) lots of questions about Delphi and things that a lot of devs would have trouble answering, and I'm quite amazed at the responses I've been getting. I think StackOverflow has met its match! It even does a decent job of explaining what the code is doing. Here's one I thought I'd share. -------------------------------------------------- In Delphi, is there any kind of an adapter or class that takes a TList<T> and makes it look like a TDataSet? [I had no idea there was such a thing as TListDataSet component in Delphi!] Yes, you can use a TListDataSet component in Delphi to make a TList<T> look like a TDataSet. Here's an example: uses System.Classes, Data.DB, Datasnap.DBClient; type TMyData = class // Define the fields in your class FField1: string; FField2: Integer; FField3: TDateTime; // Add more fields as needed end; var MyList: TList<TMyData>; MyDataSet: TClientDataSet; MyListDataSet: TListDataSet; begin // Assume MyList is already populated with data MyDataSet := TClientDataSet.Create(nil); try // Define the fields in the TClientDataSet MyDataSet.FieldDefs.Add('Field1', ftString, 50); MyDataSet.FieldDefs.Add('Field2', ftInteger); MyDataSet.FieldDefs.Add('Field3', ftDateTime); // Add more fields as needed MyDataSet.CreateDataSet; // Iterate through the TList<T> and add each item to the TClientDataSet for MyData in MyList do begin MyDataSet.Append; MyDataSet.FieldByName('Field1').AsString := MyData.FField1; MyDataSet.FieldByName('Field2').AsInteger := MyData.FField2; MyDataSet.FieldByName('Field3').AsDateTime := MyData.FField3; // Set more fields as needed MyDataSet.Post; end; // Create a TListDataSet and set it's DataSet property to the TClientDataSet MyListDataSet := TListDataSet.Create(nil); MyListDataSet.DataSet := MyDataSet; // Now you can use the TListDataSet like a regular TDataSet MyListDataSet.First; while not MyListDataSet.Eof do begin // Do something with the data MyListDataSet.Next; end; finally MyListDataSet.Free; MyDataSet.Free; end; end; In this example, we create a TClientDataSet and define the fields in the dataset to match the fields in TMyData. We then iterate through the TList<T> and add each item to the TClientDataSet. Finally, we create a TListDataSet and set its DataSet property to the TClientDataSet, allowing us to use the TListDataSet like a regular TDataSet. Note that if your TMyData class uses properties instead of fields, you'll need to use the FieldByName method to set the field values in the TClientDataSet, like this: MyDataSet.FieldByName('Field1').AsString := MyData.Field1; MyDataSet.FieldByName('Field2').AsInteger := MyData.Field2; MyDataSet.FieldByName('Field3').AsDateTime := MyData.Field3; // Set more fields as needed How can the fields be defined by using RTTI on the type of object in the list? You can use Delphi's RTTI (Run Time Type Information) to automatically define the fields in a TClientDataSet based on the fields in your class. Here's an example: uses System.Classes, System.Rtti, Data.DB, Datasnap.DBClient; type TMyData = class private FField1: string; FField2: Integer; FField3: TDateTime; public property Field1: string read FField1 write FField1; property Field2: Integer read FField2 write FField2; property Field3: TDateTime read FField3 write FField3; end; var MyList: TList<TMyData>; MyDataSet: TClientDataSet; MyListDataSet: TListDataSet; MyCtx: TRttiContext; MyType: TRttiType; MyProp: TRttiProperty; MyFieldDef: TFieldDef; begin // Assume MyList is already populated with data MyDataSet := TClientDataSet.Create(nil); try // Use RTTI to define the fields in the TClientDataSet MyCtx := TRttiContext.Create; try MyType := MyCtx.GetType(TypeInfo(TMyData)); for MyProp in MyType.GetProperties do begin MyFieldDef := MyDataSet.FieldDefs.AddFieldDef; MyFieldDef.Name := MyProp.Name; MyFieldDef.DataType := MyProp.PropertyType.HandleToFldType; end; finally MyCtx.Free; end; MyDataSet.CreateDataSet; // Iterate through the TList<T> and add each item to the TClientDataSet for MyData in MyList do begin MyDataSet.Append; // Use RTTI to set the field values in the TClientDataSet MyCtx := TRttiContext.Create; try MyType := MyCtx.GetType(TypeInfo(TMyData)); for MyProp in MyType.GetProperties do begin MyFieldDef := MyDataSet.FieldDefs.Find(MyProp.Name); if Assigned(MyFieldDef) then begin MyDataSet.FieldByName(MyFieldDef.Name).Value := MyProp.GetValue(MyData).AsVariant; end; end; finally MyCtx.Free; end; MyDataSet.Post; end; // Create a TListDataSet and set it's DataSet property to the TClientDataSet MyListDataSet := TListDataSet.Create(nil); MyListDataSet.DataSet := MyDataSet; // Now you can use the TListDataSet like a regular TDataSet MyListDataSet.First; while not MyListDataSet.Eof do begin // Do something with the data MyListDataSet.Next; end; finally MyListDataSet.Free; MyDataSet.Free; end; end; In this example, we use TRttiContext and TRttiType to iterate through the properties of TMyData and define the corresponding fields in the TClientDataSet. We then use TRttiContext and TRttiProperty to iterate through the properties of each item in the TList<T> and set the corresponding field values in the TClientDataSet. Note that this example assumes that the properties in TMyData have the same names as ... It choked at this point, but the answer is fairly complete. Curiously, I ran it again to get it un-stuck, and this time it came up with a slightly different take on defining the fields: MyDataSet := TClientDataSet.Create(nil); try // Use RTTI to define the fields in the TClientDataSet based on the properties of TMyData Ctx := TRttiContext.Create; try Typ := Ctx.GetType(TMyData); for Prop in Typ.GetProperties do begin FieldDef := MyDataSet.FieldDefs.AddFieldDef; FieldDef.Name := Prop.Name; case Prop.PropertyType.TypeKind of tkString, tkLString, tkWString, tkUString: FieldDef.DataType := ftString; tkInteger, tkInt64: FieldDef.DataType := ftInteger; tkFloat: FieldDef.DataType := ftFloat; tkEnumeration: FieldDef.DataType := ftBoolean; tkVariant: FieldDef.DataType := ftVariant; tkClass: if Prop.PropertyType.AsInstance.MetaclassType = TDateTime then FieldDef.DataType := ftDateTime; // Add support for more property types as needed end; end; finally Ctx.Free; end; MyDataSet.CreateDataSet;
  6. David Schwartz

    New to delphi - coming from web

    TMS WEB Core lets you write code in Delphi and it transpiles it into javascript that runs in the browser. It also allows you to use a bunch of JS widget libs as well. Spend some time on their website: https://tmssoftware.com Go through their blog. Andrew has posted a ton of examples that illustrate the use of JS libs in WEB Core.
  7. Pointers are used a LOT in Delphi, they just don't _look_ like it. I don't know about Java, but in C++ and Delphi, references are things that tell the compiler it's a Pointer that is automatically de-referenced so you don't need to add any sort of syntactical sugar to do it yourself. I simplifies writing code. I'm not sure I'd go as far as saying it "used for higher level abstraction". In C++ you get the same effect defining parameters on functions as references (eg., "int & abc" as opposed to "int * xyz"). Inside of the function, you'd refer to the contents of abc by simply saying "int x = abc" but for xyz you'd say "int x = *xyz". If you have a bunch of references in a nest of classes in C++, you might see "x = aa.bb.cc.dd" whereas if they were pointers the line might be written as "x = aa->bb->cc->dd". The difference is only in how the code is written, and the fact that references cannot be treated like pointers. Same in Delphi: vars that refer to instances of classes are all "pointers", as opposed to vars that refer to record types. That is, classes automatically use pass-by-reference semantics while everything else is pass-by-value. When I started using C++, I found references to be quite refreshing to use because most of the time they simplified the code. I loved Delphi for the same reason -- allocating records and manipulating them in Pascal was always confusing to me. The implicit use of references for class types makes programming in Delphi a lot simpler than if you have to explicitly use Pointers and all of their associated syntactical sugar. In the last version of TurboPascal (TP7 IIRC), they introduced something called "object" that was similar to a "class". I _think_ that's when they introduced the use of references in the compiler so when you had something defined as type "object" that told the compiler it was a pointer but you didn't need to use the ^ thingie to dereference it. They get ugly (and confusing) pretty quickly, as can be seen in C++ when you use pointers. Delphi was originally supposed to be TP8, but they changed the name. Delphi introduced a "class" and everything defined as such was in fact derived from this base object called TObject. If you say, "type abc = class ... end;" it means the same as "type abc = class(TObject) ... end;". Also, in Delphi, anything derived from TObject (meaning it's a "class") is assumed to be a Pointer and is automatically de-referenced by the compiler to simplify the code. That's not true of "object" types. The old "object" type is still there, AFAIK, but it's more like C++ classes in that respect -- that is to say, they aren't derived from anything by default. As far as compiler design goes, you'll learn there are mainly two types: a table-driven parser that uses a lexer in front, and a recursive-descent parser (which is how Pascal was originally designed to be parsed). Delphi will work for either one, but the tools used to generate code for lexers and parsers today generally don't give you Pascal as an option. Just remember that compilers are just fancy Finite State Machines (FSMs). You might never have the need to build a lexer and parser for anything, or even a recursive-descent parser, but it's very likely you WILL run into situations where a FSM is the best tool for a particular job. (I hate it when people say, "I've never written a compiler in 30 years!" and I ask, "Well, how many times have you implemented complex control apps using FSMs?" and they usually say, "Well, ... quite a few.")
  8. David Schwartz

    Unicode weirdness

    I have some PDF files that I ran through a text extractor to get simple text files (.txt). I assumed they were ASCII text, but it appears not. The files have lots of things like ’ and – and … scattered throughout. I found a table that shows what they're supposed to be and wrote this to convert them (strs points to a memo.Lines property): var ln := ''; strs.BeginUpdate; for var n := 0 to strs.Count-1 do begin ln := StringReplace( strs[n], '➤', '>', [rfReplaceAll] ); // '➤' ln := StringReplace( ln, '’', '''', [rfReplaceAll] ); // '’' ln := StringReplace( ln, '“', '"', [rfReplaceAll] ); // '“' ln := StringReplace( ln, 'â€', '"', [rfReplaceAll] ); // 'â€' ln := StringReplace( ln, '…', '...', [rfReplaceAll] ); // '…' ln := StringReplace( ln, 'â€"', '--', [rfReplaceAll] ); // 'â€"' ln := StringReplace( ln, '–', '--', [rfReplaceAll] ); // '–' strs[n] := ln; end; strs.EndUpdate; This worked for a little while, until the Dephi IDE (10.4.2) unexpectedly decided to convert all of the string literals into actual Unicode characters, and then it stopped working since StringReplace didn't find any of them in the text. Ugh. I corrected it here before pasting this code, and hopefully it won't get changed here as well. For my purposes, these characters are irrelevant. I'm replacing them with ASCII characters so they make sense if you're reading the text. But whether they're ASCII or Unicode doesn't matter. I found a table here: https://www.i18nqa.com/debug/utf8-debug.html and it says an apostrophe can be represented in several ways: How can I replace a 2- or 3-char literal like â € ™ with one of these above codes so the compiler doesn't change them back to Unicode representations? Is there a simpler way to do this? Depending on what I'm using to look at the text data files, they may appear as their "real" Unicode representation, or they may appear as 2- or 3-char gibberish. I just need ASCII text that comes close to what they represent.
  9. I have never seen a project fail because someone did not understand some fundamental data structure. However, I've seen plenty fail because they cannot listen to users and document what they said they wanted; because they cannot write clear specs that don't have holes in them; because they can't write code without making assumptions about edge cases because they're afraid to let their boss or client know there's still stuff they're unclear about; and I've seen lots of wasted efforts because even though we implemented exactly what the client asked for, when they saw it actually run, they decided it was totally useless -- because management refused to allow us to get into any kind of dialog with the clients to help clarify their actual use case needs. As a point of fact, very few people I've met who were "self-taught" have ever had any exposure to fundamentals like what we learned in core Computer Science classes. Nonetheless, an increasing number of companies are now hiring people with degrees in English Lit, History, and Psychology, and teaching them how to program. I've been wondering for a while now how relevant the core parts of most CS curricula are since most of it was an outgrowth of an era when both CPU cycles and memory space were far more expensive than programmer time. It's a sad fact that too many programmers with CS degrees will sit down and write a sort routine themselves rather than use a library, mainly because they just don't know what's available in the various libraries they have access to. (In college, we were given bonus points for writing code that had fewer lines and/or took less memory space that the average. We were not rewarded for completing assignments quickly and completely using whatever tools we could find. "Time-to-market" is a very important metric for most companies that rely on software; it's also antithetical to what's taught in most CS programs.) In fact, I'd be far more concerned about a job candidate who didn't know there are generics for all sorts of containers than whether they know how to implement a single- or doubly-linked list in Pascal. Sorry. I don't know how many times someone might think they need to implement a linked-list from scratch; but there have been plenty of times when I was told to do something within a time-frame that would be undoable if I had to rely on core concepts I learned in school rather than specialized libraries that would let me solve the problem in a fraction of the time. So we can agree to disagree on this stuff.
  10. There's been very little need for pointers in Delphi after they made it so objects are implicitly passed by reference. People still use them with Record types. As an aside, I've been working with TMS WEB Core a lot lately. It transpiles the Dephi code to javascript, and js doesn't support pointers. So it won't compile Delphi code that uses pointers. Aside from the fact that TTreeNode's have a Data property that's typed as Pointer, I've not had any problem at all. I urge you to learn what's in the RTL and how Generic collections work rather than reinventing the wheel. There are far more interesting problems you can explore besides data structures invented at a time when CPU cycles and memory were very expensive compared to the cost of programmer time. The most commonly used class in Dephi is the TStringlist. It's like the "Swiss Army Knife" of most Delphi programming. Spend time playing with every property it has and get to know it inside and out; I promise you it will be time far better spent than messing with basic data structures. BTW, something not a lot of Dephi programmers know is that a TStringlist can be used to manipulate CSV files directly. You can make them multi-dimensional by hanging them off of the Objects property in a base object. You can also make a wrapper class that defines properties to make it much simpler to access things stuffed into those Objects 'arrays'. When I was learning C++, there was a book, "C++ Idioms" that I referred to a lot to learn different types of common coding idioms and patterns. A lot of them are really OOP patterns that apply in many languages, although many are specific to C++. Spend time learning Delphi programming idioms, especially the different ways of declaring properties and when it's good to access local fields directly rather than setting every property up to use getter and setter methods. And avoid getting into the habit of putting business logic inside of event handlers! Make a separate method that's called if you need to interact with other UI objects as a result of an event being triggered.
  11. David Schwartz

    Unicode weirdness

    Ok, thanks for all of this juicy info. I've learned a bit, but I'm still not sure what to tell someone who sends emails or posts things that have words with apostrophes in them that look like: I’m can’t won’t and so on. I've solved my problem, but that’s not it. 🙂 I've also found that if you load things that look like this <break time='5s' /> into TMS WEB Core visual controls, they get eaten up because the browser apparently thinks they're XML tags or something like that. So I changed them to this «break time='5s' /» which works great. And, yes, I tried &lt; / &gt; but they got automatically converted and THEN the whole "tag" got eaten up. <sigh>
  12. David Schwartz

    Unicode weirdness

    That was not an option on the extraction tool; you upload the file, it processes the file, then you click a Download button. Yes, but how can I do that? Because they are unnecessary. Deleting them would make no difference to the result I'm after. But having them as weird text IS a problem.
  13. David Schwartz

    Unicode weirdness

    You guys are totally missing the point here. The code in the Delphi IDE looks like this: ln := StringReplace( strs[n], '➤', '>', [rfReplaceAll] ); // '➤' ln := StringReplace( ln, '’', '''', [rfReplaceAll] ); // '’' ln := StringReplace( ln, '“', '"', [rfReplaceAll] ); // '“' ln := StringReplace( ln, 'â€', '"', [rfReplaceAll] ); // 'â€' ln := StringReplace( ln, '…', '...', [rfReplaceAll] ); // '…' ln := StringReplace( ln, 'â€"', '--', [rfReplaceAll] ); // 'â€"' ln := StringReplace( ln, '–', '--', [rfReplaceAll] ); // '–' This code works fine. And at one point I opened Delphi and the same code now looks like this: ln := StringReplace( strs[n], '➤', '>', [rfReplaceAll] ); // '➤' ln := StringReplace( ln, '’', '''', [rfReplaceAll] ); // '’' ln := StringReplace( ln, '“', '"', [rfReplaceAll] ); // '“' ln := StringReplace( ln, '”', '"', [rfReplaceAll] ); // '”' ln := StringReplace( ln, '…', '...', [rfReplaceAll] ); // '…' ln := StringReplace( ln, '—', '--', [rfReplaceAll] ); // '—' ln := StringReplace( ln, '—', '--', [rfReplaceAll] ); // '—' This code DOES NOT WORK! My text does NOT contain these Unicode characters! It contans 2- and 3-char representations. I even tried something like this: ln := StringReplace( ln, 'â'+'€œ', '"', [rfReplaceAll] ); // '“' It did not work either.
  14. David Schwartz

    Unicode weirdness

    I don't want or need them in Unicode -- I want plain ASCII or Ansi Strings. That's what I'm trying to do here -- the problem is the IDE is changing the MBCS back to Unicode, so the StringReplace isn't doing what I want it to do. I'm wondering how to rewrite the StringReplace calls so they match the actual text, but the IDE won't translate them into Unicode?
  15. David Schwartz

    E2137 Method not used in base class

    How long have you been programming? Back when C++ was introduced, the general rule-of-thumb was that for people who had been doing regular procedural programming for a while, it would take about 6 months to really grok what OOP was about. I had to just keep writing code and writing more code until after 5 months or so, one day something in my head went "ping!" and all of a sudden I "got it". I've heard similar atuff from a lot of others as well. Since the mid-90's or so, OOP has been taught in college courses right from the beginning, so there are people who never knew anything different. Once I'd learned OOP, working with a non-OOP language has been hard. There are still people who write php and refuse to use any of the class-related language features, and their code is ugly as hell, exactly what you'd expect without leveraging language features to at least manage encapsulation. It would be nice if they'd teach Delphi's Object Pascal in colleges today, because it IS fully object-oriented, and it IS easy to learn and code with. I don't think you need a tutor, you just need to keep writing code. Try translating some old C libraries into Delphi libs using classes. Or even old Pascal libraries. Part of what I did was took some C libraries I was using and turned them into OOP-based libs. I kept writing these huge, complicated classes and would inevitably code myself into a corner where I had nowhere to go, no way to access a piece of data I needed, and just couldn't figure out why? When the light bulb went off, I deleted all of that code and started over from scratch, and it ended up seemig really simple. Somebody tried explaining it to me once before my brain had adjusted to working with OOP yet, so what they said went in one ear and out the other. Just keep coding just keep coding code code code code code code code code One day you too will have the "OOP ephinany" and it will suddenly make perfect sense!
  16. David Schwartz

    Dealing with multiple component versions using the same ide

    The problem with this is there are both files on the disk as well as entries in the Registry that need to be changed -- AND kept in sync! MAYBE you could get by just by changing Registry entries if you were really crafty. The safest thing might be to create separate user logins for each Dephi configuration and install on a per-user basis. But that will eat up a HUGE amount of disk space before long. I've seen places I've worked solve it by having virtual machines they'd RDP into that were configured differently, but only one person could be using one machine at any given time.
  17. David Schwartz

    Choosing a Mac

    I'm unclear what sort of configuration you're looking at, but I'll share what I'm doing. I have a couple of Mac Minis that I use, as well as a MacBook Pro. All of them use Intel Core-i7 CPUs. I run Win 10 in a VirtalBox VM that I mainly run on a 2018 Mac Mini. I used to run on the older one (2014) but it's mainly used just for email now. I use multiple Spaces (ie, virtual desktops) and have #10 (ie, <ctrl>-0) configured to run MS RDP to connect to the older Mac Mini. I works fine for my needs. As side note, the Apple equipment all has 1GB Ethernet built-in, and I have a 1GB switch I plug everything into with Cat6 cables. That's a whole lot faster than going through WiFi with my router, and cheaper than buying a much faster router. I have to use RDP to access a remote Windows host and that's slow enough. Trying to connect my machines via my WiFi router is even slower. I have Delphi 10.4.2 installed in that VM, and have used several older versions as well. But the VM gets really bloated when you add multiple Delphi versions to it. I suggest making one Win VM and clone it, installing just one version of Delphi in each one. Then get a Samsung T5 or T7 SSD drive to off-load the VMs you don't need. The T7 might be fast enough to use in place of the built-in SSD. (These things really scream!) I've built software that runs outside the VM on MacOS just to play around, but nothing serious. I've also used CrossOver to host Win apps in MacOS, and it works surprisingly well. (Not for Delphi, but for apps I've built.) It seems a lot easier to deal with once you figure it out. I have a Z: drive set up that lets me access the host's file system and I backup files to it periodically. I also have a large backup drive connected to run Time Machine once a day. I have Dropbox configured in the host, and I use it to move files between computers. I don't run it inside of the VM because that seems redundant. I can easily reach it from Z:/dropbox when needed. I've read that people use a Mac Mini as a test environment, connected to a Windows laptop, but ... why? I used to do my dev work within VirtualBox on my MBP with a larger monitor connected, but it's a 2014 version as well, so the 2018 Mac Mini is generally faster. A newer MBP would probably do everything you need in a laptop. I'm not sure about using an M1 or M2 in the host and how that might affect the VM. Supposedly MS has a version of Windows that runs natively on ARM, and the Mac has an emulator for Intel CPUs that's invisible, but ... you'll have to figure that out yourself. Does D11 have a way to target both Intel and ARM CPUs for MacOS? I don't think D10.4.2 does. CrossOver does support the M1 chip.
  18. David Schwartz

    Delphi's __recovery folder

    I spent an hour on some form design work in Delphi (10.4.2) and then at one point where I started to select several objects on a form holding down the Shift key, it went out-to-lunch. I had to kill it from the Task Manager. I noticed the files for the form I had been working on were in the __recovery folder. But when I reopened Delphi, it showed an hour-old version of the form. I went to the Explorer window that showed the form files, and tried to copy them, but I got an error saying they weren't there. I refreshed the display and they were gone. I even tried to use an app to undelete files, but they were gone. How is this thing supposed to work? I've had it recover files in the past, where it opens a project then asks if I want to recover a file or two, but in this case it never asked. It seems to have just deleted the contents of the __recovery folder.
  19. Yes, I did read the article. I was referring to all of the posts made here in this thread earlier about how chatGPT isn't 100% perfect, so therefore it's a waste of time to even think about using it -- at least, that's my interpretation. If this tool uses chatGPT, then I assume the complaints made earlier about how error-prone chatGPT is (and AI in general) will apply equally to any tool that uses it. I started this discussion by showing some code that, while not impeccible, had a lot of useful stuff in it. I suspect that it's possible to get the same nonsense out of the tool mentioned in that article unless the inputs are highly constrained. ChatGPT happily accepts unconstrained input, and seems to make unfounded inferences that it uses to create nonsense output. Kinda like what most people I know do from time to time. But if the argument is that AI-based systems should protect against stupid questions that will prevent it from spitting out nonsense answers, then it will never give accurate answers 100% of the time. Nor will people ... but that's another story. I didn't write chatGPT, I just entered some queries and got back some stuff that I found interesting and shared here. The folks here say it's worthless nonsense and they don't want to have to worry about double-checking the quality of responses because of that. I'd like to remind everybody that it's possible to write LOTS of code in Delphi that will compile, and might even appear to make sense, but will give random and often unpredictable results, and sometimes even no results at all. Not to mention the long list of documented errors that Delphi has, and they exist as land-mines that will periodically produce unexpected results at best and run-time errors at worst.
  20. There are also the functions in StrUtuils like IndexText/Str and ContainsText/Str
  21. This looks like the same stuff everybody above is saying is too error-prone and therefore should be totally avoided. Most code I write seems to be what I call "plumbing code" -- moving data back and forth between object A to object B -- and it's boring, repetative, and very mechanical. ChatGPT has done a great job writing examples of code like this for me. But like all coders, it's not 100% accurate 100% of the time. Earlier commenters in this thread assert we shouldn't be using it at all if it needs to have it's work constantly checked, and just crank the same mundane code out ourselves. I find this type of coding neither fun or creative. But thanks for pointing out an article that basically reinforces what I said earlier. It's sad that so many people expect 100% perfection before they'll even consider anything like this.
  22. David Schwartz

    IsNullOrWhiteSpace???

    You probably don't need the class name in front. and isn't this form also acceptable: myString.IsNullOrWhiteSpace
  23. David Schwartz

    E2137 Method not used in base class

    Object-Oriented Programming involves three distinct things: Polymorphism, Inheritance, and Encapsulation. It seems you are not grounded in these yet. (Don't feel bad, none of us knew how to walk or talk when we were born, either. There's stuff in life that just needs to be learned. 🙂 ) You didn't show the declaration for the TBaseSkillPanel class, so it's unclear if you're inheriting from something else or not. I could guess it's several things, but I'll not go there. It's either declared like this: TBaseSkillPanel = class or like this: TBaseSkillPanel = class( TForm ) -- or something other than TForm The first one is a standalone class (which in Delphi's world is really implied as saying = class(TObject) ), while the second one is derived from some other class. This is what inheritance refers to -- you're extending the base class by adding more stuff to it and giving that new combined class a different name If you're inheriting from TForm or some other subclass that defines PanelResize, then it needs to have the virtual or dynamic attribute on its declaration to allow you to then say override but it's not required. In this case, the error suggests that there either is NOT a PanelResize method in the base class, or it is not tagged with a virtual or dynamic attribute, meaning the override is misplaced -- in fact, it doesn't belong there. The flip side of this would be where the base class DOES specify virtual and the derived class does NOT specify override on a method with the same name and signature. In this case, the compiler would warn you that the "method in the derived class hides the method of the same name in the base class". Sometimes you want that, in which case instead of override, you need to specify reintroduce to avoid the warning. (This is quite common when you want to use the same method name in the derived class but change its signature, usually by adding more parameters. It's most commonly encountered on constructor Create... methods.) I suspect you think that adding methods in a derived class requires you to include the override attribute. It's only needed if there's a method in the base class with the same name and signature that has virtual or dynamic specified. That's not correct thinking. Also, the use of virtual or dynamic (although dynamic is very rarely used) signifies the possibiity of polymorphism, which is an aspect of inheritance that gives you some rather magical abilities. I suggest you learn about these three topics; they'll help you understand and organize your code much better. They are fundamental to ALL aspects of object-oriented programming, which Delphi embraces quite extensively.
  24. New technology always comes with a lot of "noise". If you're not willing to tolerate that "noise", then you can just stand by and wait while others master the underlying technology while simultaneously figuring out how to reduce the "noise level".
  25. David Schwartz

    your own DB vs. 3rd-party?

    If you're building a web app that needs to save data in a back-end DB, I'm curious about the trade-offs between buiding your own DB using MySQL, MariaDB, SQL Server, etc., versus going with a 3rd-party solution like AirTable, DreamFactory, or something similar. (Suggestions for such services are welcome.) EDIT: I stumblled onto this and they've got a bunch of 3rd-party services that they work with. (I'm pointing it out as a source of info; I don't know anything about the vendor.) https://retool.com/integrations/ Honestly, over the past 20 years or so, I've worked on plenty of apps that rely on back-end DBs of various flavors (namely SQL Server, MySQL, Oracle, and PostgreSQL), but they've all been managed by an IT Dept. In theory, there's not much required. But it seems every one has had one or two major melt-downs per year. I like to focus on what I'm best at and leave other stuff like this to people who understand it more than I do.
×