Jump to content

David Schwartz

Members
  • Content Count

    1178
  • Joined

  • Last visited

  • Days Won

    24

Posts posted by David Schwartz


  1. 9 hours ago, JonRobertson said:

    If that was directed at me personally, it should not have been.

    It wasn't. It's just a general attitude that I find quite pervasive in the programming community. 

     

    9 hours ago, JonRobertson said:

    I don't understand why a person or company that creates a product they believe would be useful to others wouldn't spent a few minutes to inform potential customers the details, including limitations, of a trial version or offer.

    Maybe because details of the trial are irrelevant to the offer itself?  When you click the link for a trial DL on most sites, it usually goes to a page where all of the TRIAL details are listed, which are sometimes (but not always) different from the MAIN OFFER. If you put them on the MAIN OFFER PAGE then people will often get the two confused and a confused mind does nothing.

     

    A lot of times, the trial offer can vary by switching out the trial DL page rather than the main sales page.

     

     


  2. Any Delphi book from D2010 and later will help you learn the language and develop basic UI skills.

     

    And they pretty much all teach the same bad habits to simplify showing how to build forms. 

     

    There are also tons of videos on YT and other sites, some of which are step-by-step tutorials, as well as lots on specific topics.

     

    Don't forget the annual CodeRage virtual conferences that CodeGear and then Embarcadero have hosted over the years. There are always a few presentations for beginners as well as lots of interesting niche topics.


  3. On 4/9/2024 at 1:57 PM, JonRobertson said:

    Nope, but I clicked the link out of curiosity. I just love commercial products that offer a trial but give no details about the trial period, expiration, or trial limitations.

     

    However, the price sounds very reasonable... if it works :classic_biggrin:

     

    I imagine you prefer visiting projects on GitHub that have no documentation at all and require you to read the code to figure out exactly what they do. But, hey, they're free, so what's a few hours of your time worth, right? And of course, besides being free everything on GitHub works perfectly and they've got terrific support, saving you even more time!

     

    FWIW, I found this tool in 2010, and the author has been regularly updating it ever since. To his credit, he charges a very modest annual fee rather than saying "free updates for life", which usually means he'll be out of business within 2-3 years.

     

    I'd encourage you to 'click the link' on most WP plugins to see how few of them have been around since 2010, and how many have NOT been updated in the past year or three.

     

    Sorry, but I don't understand why so many programmers are allergic to paying for the same stuff that they themselves get paid to do without regard for how or where those funds come from -- usually from sales of the software they write. But who's counting...


  4. On 4/11/2024 at 4:08 AM, FreeDelphiPascal said:

    Nice post David S!
    I had recently to fix a bug in a program that was sending wrong financial reports to a governmental financial institution (equivalent to RSI in America) for 18 years. After 18 years, somebody observed the problem. It ended up that there was not only one bug, like 15. Nobody ever observed the other 14 instances where data was wrong.

    I was told to shut up and move on. Also, nobody cared that my new program was running 100x faster than the previous one.

     

    I told them that probably there were another 100 bugs in there (pascal-like code, no objects, thousands of warnings and hints - at least, there were no pointers!). They wouldn't let me rewrite the program. They said, it now it works, let it as it is.

     

    So people, don't blame Delphi for not being totally memory-safe. It is mostly the programmer that dictates the safety of a language.
    I guess the programmer that wrote that program in Delphi would be able to sneak in some calamities like this also in a language like Rust.

     

     

    I can totally relate to this!

     

    At one gig I was on, I discovered some coding patterns in a quite large Delphi system that compiled without any warnings or hints, but were wrong. It was by sheer luck that the code worked most of the time, and when it didn't, it produced strange down-stream errors unrelated to the actual coding mistakes. 

     

    I tracked down over 100 instances of these patterns and tried mightily to get them fixed. At one point, I pushed out a version with about half of the issues corrected. The testing group asked what happened because my new update was running about 25% faster. They were very happy. At the end of the day I asked if they had encountered any of the random irreproducible errors they seemed to get regularly, and was told "not one!" The next day, I pushed out an update with the rest of the issues corrected and speed increased again. Also, none of the irreproducible errors showed up. But the third day I was told to revert everything because the tickets I put into the backlog weren't done properly; they wanted me to enter a separate ticket for each change. So I reverted the code and the next day the testing team was unhappy because it was running slowly again, and those weird errors were back.

     

    I kept trying to get these issues resolved, but after 9 months of this nonsense, I believe I was terminated for refusing to stop.

     

    At one point, someone suggested that, for this particular project, the company had guaranteed to the client that it was "bug-free", although any errors they found and could give us code that reproduced the error, then it would be fixed.  For all my efforts, all that happened was that more stringent rules were published about who can submit bugs, and ultimately the Dev Team was explicitly prohibitied from introducing either bug or refactoring tickets into the backlog (even though we supposedly "owned" the backlog). A few days before I was let go, word came down that every single line of code that was changed had to have a comment tying it back to a specific ticket in the backlog, and an audit of said changes was added to our sprint completion meetings. 

     

    To make matters worse, there had been dozens of reports of a certain type of error that was not reproducible, and part of what I discovered explained this -- it was a data-sensitive error, and feeding the same data in repeatedly via the UI did not produce the exact same result in terms of what the erroneous code was looking at, so it was not reproducible. 

     

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

     

    To this day, nothing has been done to the Delphi language that would help these issues be detected and reported by the compiler. I have no idea if this code ever went into production or not, but those 100+ coding errors were bugs waiting to be triggered. I only found them by accident, stumbling into some code that looked odd but actually compiled.

     

    After a while, it suddenly made sense when I looked at from another perspective -- one that was specific to the main programmer's previous experience and the language he used for several years prior to working with Dephi. Reading bits of that code as if it was written in that other language was exactly what he expected the code to be doing. Delphi considered it syntactically ok, but it was nonsense from a semantic standpoint, although Delphi didn't care about that part. I even ran samples of this code through some Pascal code analyzers and they didn't catch these errors either.

     

    Unfortunately, backtracking from the points where the faults were raised was fruitless. 


  5. On 4/9/2024 at 12:18 PM, Brandon Staggs said:

    I'll avoid direct pointer math when I can, but when you need to drive video, text, and geometry effects dynamically, live at 60fps, it helps to know theses things and use them where optimization is needed.

    Pretty much any programming language that lets you do bitwhacking can do this. Just like anybody can walk on their hands or ride a unicycle with some practice. The question is, "Why?" Just because you can? Most people would argue that C is far better for this sort of thing. 

     

    Sure, Delphi already does this, but I don't see it being used as a language of choice by devs who do a lot of bitwhacking, like gamers.

     

    But at some point, this becomes a circular argument: Why doesn't Dephi support language features that most contemporary languages now include? Because nobody uses Delphi for that purpose. Why is that? Because it's too inefficient without the built-in language support. As if that's going to encourage the Powers That Be to take an "Add it and they will come" attitude...


    I want to see enhancements that make the language safer, and make it easier to use with less verbiage for things that other languages now routinely support. Constantly offering-up verbose and unsafe workarounds is not encouraging to anybody.

     

    • Like 1

  6. 12 minutes ago, David Heffernan said:

    The real trick there is not to do it. Avoid it at all costs.

    So what DO you do in a case where, say, you might use an object to collect an accumulation of data that is provided by multiple sources? 

     

    It's often done for contextual state management over time...

     


  7. Has anybody played with AppGini from BigProf Software? I've built several small DB-based web apps with it, and you can do quite a lot without having to write any code. The UI isn't anything to write home about, but unlike most low/no-code platforms, it generates php/MySQL code that runs totally on its own.

     

    https://bigprof.com/appgini/

     

     

     


  8. I've not been following this, but it seems what they're saying is "the beta-test is ending" and they've got a slightly different way of naming things now.

     

    BTW, can you recommend any resources that discuss different aspects of writing prompts? I mean, are there any clear patterns defined for "prompt", "meta-prompt" and so on? They seem to be a combination of "macros" and "procedures". Most of what I find is just long lists of different types of prompts that people have written. 


  9. 20 minutes ago, David Heffernan said:

    It's odd you say that, but I never have to debug issues like this. There are two simple patterns for lifetime and they are so ingrained, nobody ever makes a mistake in my team.

     Well, the two patterns I can think of are: (1) when you have everything contained within a single method; and (2) when you're working with an object that has an unpredictable lifetime and lots of methods are touching it.

     

    I encounter errors in (1) when the code is rather long and I declare an object but forget to add the Free to the Finally clause.

     

    For (2), I'd love to see what your approach is. I've not found an approach that is robust and works well everywhere, other than something that takes a lot of extra code to check things everywhere.

     

     


  10. Einstein is credited with saying, "Everything should be made as simple as possible, but no simpler."

     

    There are usually three steps in most non-trivial algorithms:

     

    * declaration / initialization (can be optional)

    * process

    * destruction (may be automatic)

     

    I like it when each of these is clearly identifiable. I get nervous when the class designer tried to be too cute and save me from typing a line or two of code, so I end up wasting time digging into the code to see what's being done implicitly. Eg., sometimes there's an implicit object being used that you need to copy stuff into before anything will work. Sometimes the result set is in a (hidden) object that you need to deal with, starting with whether it's even valid or not.

     

    You can shuffle things around in many interesting ways to simplify how much code you need to write in different places, but just be sure it's clear and unambiguous so when you look at it in six months you can quickly figure out what it's doing. None of these three examples does a good job of that, IMHO. 


    Unless you're passing in an already prepared query object, then you need to prepare it -- that the first item.

     

    If it succeeds, then you want to process the query, typically iterating over what might well be 'n' result sets.

     

    Finally, you want to free up the object(s), although this may be done automatically.

     

    So for me, Pattern 1 fits this best with the separate Prepare statement, but the 'process' part can be improved.

     

    Try this approach and see how you like it. Note that this doesn't conflict with what Nick teaches. Just don't try to do everything in one statement. 🙂

     

     

     


  11. Ok, all of these nuances aside, I for one would LOVE to see something added to the Delphi language that DOES make it more "memory safe", specifically an option that let you tell the compiler (simply in the declaration) that some var is to be treated local to a block and to free it at the end of the block, without requiring try...finally. C++ has done that forever, as well as many other languages. 

     

    Off-the-cuff, maybe something like this:
     

    function get_users_name : string;
    begin
      Result := '';
      local tmpForm := TUserNameForm.Create(...);
      // set some properties
      tmpForm.Caption := 'Enter name';
      . . .
      if tmpForm.ShowModal = mrOK then
      	Result := tmpForm.aName;
    end;

     

    tmpForm will be automatically freed at the end of the block and the memory cleared. 

     

    I'd like this because chasing down orphaned blocks and references to objects that got deleted early seem to take up more of my time than any other types of debugging issues. I want more help from the compiler and language for this common situation using LESS CODE! Maybe we'll see something when Delphi turns 30 next February?

     

    The try...finally, Free, and clearing memory are all managed implicitly by the 'local' variable designator (as an example).

     

    It only needs to work initially with normal TObject references (including lists), and arrays of anything (including Objects).

     

    If you declare 'local' scalars, they'll be cleared at the end.

     

    For pointers, just come back later and use AI to figure out what's going on with the pointers so the code can help deal with them.

     

     

     


  12. On 3/12/2024 at 7:30 AM, Brandon Staggs said:

    Nevertheless, all of the non-trivial projects I work on make use of pointer math too. What you say about pointer math, speed, and what companies want, may be true in many cases, but extrapolating from that to your original claim about pointers (math or aliases, regardless) is quite a leap. They have not "pretty much disappeared from use." One example that comes to mind is a custom 8-bit bitmap backing we developed that would be excruciatingly slow were it not for basic, simple, tried-and-true pointer arithmetic.

     

    The reality is also that even libraries that don't offer access to these programming methods still make use of them internally. Somewhere, someone is doing the pointer math.

    I have not used any calculus since college. I've never had a job that required it. I know I'd be remiss in asserting that calculus must be a dead part of math in the same way that Latin is a dead language, as I'm confident there are plenty of projects where their programmers are implementing solutions to calculus problems on a daily basis. However, I seriously doubt they're using Delphi to do so. (queue up those here who want to tell me otherwise...) FWIW, I've known plenty of programmers who do nothing but write highly-performant code that implements math functions I can't begin to explain, most of which employ calculus. And not one of them said they used Dephi. The most commonly used languages they mentioned are C, FORTRAN, and MATLAB. For those who've looked, Delphi has far too much "compiler overhead" added to the code it generates. 

     

    Likewise, I'm confident that there are plenty of problems that can be written without pointers and bit-whacking, but if you want to drop down to that level, then the program will definitely run much faster. 

     

    And if you go all the way down to Assembly language, they'll run even faster.

     

    Does this mean that we should avoid adding features to the language that the vast majority of people who write Delphi code would find beneficial, simply because some tiny percentage of users aren't served by them because of hand-optimized code that uses pointers?

     

    I've probably seen millions of lines of Delphi code in my career, and aside from a few isolated routines here and there, there was no use of the ^ operator anywhere, indicating a very broad lack of employing pointers simply because they run a little faster. Sure, pointers are heavily used in the RTL and common libs that I think SHOULD be highly optimized. But the people responsible for them are the library vendors, not end-users.

     

    This attitude is probably why there have been so few changes to the Delphi language over the years. The industry considers Delphi fairly "ancient" because it's lacking so many features that most contemporary programming languages have. Those features were added to help a majority their of users, not 100%. Nothing seems to get added to Delphi's language unless it benefits as close to 100% of users as possible. 

     

    When Delphi was introduced, many of it's features were state-of-the-art. Today, it's almost an anachronism. Nobody teaches Pascal any more, and features found in most languages used today are probably years away from showing up in Delphi, if they ever do.


  13. 17 hours ago, Lars Fosdal said:

    MS Copilot might be able, but, yeah, elbow grease FTW.

    If I open the list as a text file in Chrome or Opera, I can highlight the company name and it offers a popup to Search, Copy, and Share. I just click Search and it finds the website pretty quickly -- far faster than the Google SERP scraping tool I've got.

     


  14. 16 hours ago, Brandon Staggs said:

    That's a pretty bold statement. All of the non-trivial projects I work on make use of pointers. Saying they have "pretty much disappeared" is a bit of a stretch in my experience.

    Sorry, y'all are obviously not reading my mind correctly. I was not referring to simple Pointer Aliases.

     

    TL;DR -- Pointer aliases are inconsequential. Pointer math is extremely hazardous. In my experience, companies couldn't care less about making code run faster ... not a "little bit" (minutes saved) nor a "huge amount" (hours saved). Nothing justifies using pointer math in Delphi apps to make apps run faster due to the likelihood of errors that the compilar nor test suites can catch. Desktop apps are far different from real-time process control apps, or even the libraries used in them; NOBODY cares about making them run "a little faster" that a newer faster computer won't fix

     

    I was referring to constructs like this (and I may not have even used them properly):

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

    var pXyz : pointer;  <----

    var xyz: integer;

    pXyz := ^xyz;  <----

    var i : integer;

    var myIntAry : array [0..maxVal] of Integer;

     

    for i := Min(myIntAry) to Max(myIntAry) do

    begin

      // this is an example of what I was referring to that's used frequently in C and C++

      ^pXyz := Random(1000);

      inc(pXyz);  

    end;

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

    ((sorry, the insert Code thing isn't working))

     

    Yes, I realize Pointer aliases are used a lot in the VCL source code, but most of that was written in the 1990's and probably hasn't been updated much since then. ("If it ain't broken, don't fix it.") I also realize that Delphi class vars (eg, myClass : TMyClass) are basically pointers treated as references (like C++: TMyClass : &myClass = new(TMyClass); )

     

    The pointers of concern (that use the ^ operator the same way C/C++ uses the * operator) are also the code used any time you have a Record that's allocated from the heap.

     

    The thing is, some people still obsess over a few extra instructions that the compiler might generate that can be eliminated using pointers, but I suspect most of them are "old school" programmers from way back in the day when every CPU cycle and byte of memory that could be saved were significant. When programs were 50k, they could be copied to a 128k floppy for distribution, and nobody ever imagined a computer would need more than a few MB of RAM. I was taught that way, but shook off that habit in the 90's. 

     

    Today, desktop computers ship with 8 GB or more of RAM. (My first HDD was a whopping 10 MB!) The CPUs are multi-core and have hyper-threading, and if you try to out-guess the compiler's optimizer, the code is more likely than not to run slower due to all of the NOPs injected into the instruction cache. All of that hand optimization is likely to work on only ONE CPU (or CPU family) and will need to be revised for every difference in number of cores, instruction cache size, and maybe even data cache size. 

     

    I know there are always "exceptions". MOST people creating form-based desktop apps that interact with a back-end database using Delphi are NOT writing code like that! They _might_ declare a pointer alias here and there, but they certainly aren't writing code that anybody will notice if it runs 100ms faster.

     

    At my last job, I was told to "port' something that was written for use by one specific client. It ran once a day and took a bunch of daily invoices scanned into PDF files at a dozen or so sales offices, with hundreds of pages saved into each PDF. It ran some OCR on each page and attempted to read an Invoice# from each one and then put the pages for each invoice into a separate PDF so the customer could view the pages for each invoice online if they wanted to, with all of the pages for that invoice in a single PDF file. It used a Version 1.0 DLL from an OCR app from 1997 that ran under WIndows 98 when it was released. This was 2018 and the code didn't run properly under Win10. For years, this thing ran in an hour or so. When I got hold of it, it took 8 hours to process a thousand or so invoices daily. I also discovered that it was unable to process about 30% of the invoices it was given and simply skipped over them. I completely rewrote it using a much newer OCR library written in Delphi, and my version ran in about 45 minutes for the same data that took the older one >6 hours. NOT ONE PERSON CARED THAT IT RAN SO MUCH FASTER! NOT EVEN THE CLIENT! In fact, my boss made a note on my annual review that this task took me 2 months to complete while they believed should have taken a week or two. (Never mind that their analysis was totally off-base.) The client rep contacted our support wondering why there were suddenly so many more invoices showing up every day in the process summary. I told our internal support person it was because the old code was not processing about 1/3 of them. When she told the client, they said, "Oh, ok. That's good to know." That was it. In use for over 15 years, they never noticed anything was wrong.

     

    This is hardly an isolated experience I've had over the past 25 years writing and maintaining Delphi desktop apps for clients. Nobody really cares about even significant performance issues, and most don't notice small problems. Very few ever audit their data, either.

     

    I worked at one place and discovered that medical invoices were being printed out and some separator pages were missing, and so customers were being mailed health records for other people accidentally stuffed into their envelopes, and nobody at our company that did the printing and mailing, nor the client company, ever knew! This should have been treated as a MAJOR HIPAA violation, but I was told to keep my mouth shut and just fix the problem.

     

    You guys outside of America might be wondering how this happens, but from my experience, it's quite common. Every job and contract I've had, I've found at least one and sometimes dozens if not hundreds of things that had been operating improperly for years. Some were performance-related, but most were just data integrity problems. Management mostly did not want to hear about it. 

     

    So I really don't want to hear about all of the exceptions and reasons why it's important to shave 50 ms off of the execution time of some loop you may be working on. The last place I worked printed bills and invoices, stuffed them into envelopes, and sent them out to the US Post Office -- 7 or 8 full 40' semi-trailers EVERY DAY, 7 days a week. They got pissed off if part of a line on an invoice was cut off on a print run of 50,000 invoices; not whether it took an extra 15 minutes to run a given print job, as long as the people who got the materials could read them and they looked "professional".

     

    If customers didn't complain, that meant nothing was wrong. Nobody cared what we programmers might find.

     

    One thing I've found over the past 15 years is that Management is far more scared of allowing programmers to refactor code than just about anything else. Because trying to shave a few seconds of processing time often leads to bugs that did not exist previously. And yes, that's because they don't have comprehensive test suites (which are notoriously hard to write for form-based Delphi apps).

     

     

    • Like 1

  15.  

    On 2/25/2024 at 10:11 AM, Lars Fosdal said:

    In theory, the AIs might be able to pull out such data.

     

    As I said, I am using AI to pull out the company data, but ChatGPT4 can't access the internet directly.

     

    Turns out that it's probably easier to just do it by hand in small batches.


  16. I didn't dig very deeply into the nuts and bolts of this issue, and was quite surprised to see Delphi on the list. 

     

    I read a lot of comments in the post I found, and it looked like the main thing people were objecting to vis a vis C and C++ is the highly idiomatic use of pointers to iterate through lists, which is so pervasive that it is found all over the STL and many common libraries. Such pointers aren't considered type-safe unless you tell the compiler to check them, so that could be the root of the problem.

     

    While Pascal has Pointers, they have pretty much disappeared from use, except in highly-optimized code (which may be CPU-specific) and where Record types are employed. 

     

    On the flip side, I can see why the White House might want to make an exception for Delphi since the VA may be the largest single organization in the world that's still heavily dependent on Delphi -- that and MUMPS. There are tons of vendors that are required to write Delphi apps that interface with their systems, and they're required to support them for ... decades (?).

     

    I worked at a company 12 years ago that's still in business writing and maintaining code for the VA that's all written in Delphi and MUMPS. And every few months I see jobs posted on various job boards that are looking to hire contractors to work on projects with the VAs signature all over them. (They're looking for Delphi devs with some MUMPS exposure, familiarity with VistA, and a few other "code words" in the job reqs that give it away.) The VA's Delphi code is not going away any time soon, and continues to grow.

     

    The point being, excluding Delphi would force Congress to invest a HUGE amount over the next decade to replace all of the Delphi code currently used in the VA. The Good News, however, is that by avoiding the use of pointers (which most of us do anyway) reduces the risk (that they seem to be focused upon) quite a bit.

     

    That said, I found code examples in the code base I was working on that were written by a MUMPS programmer who learned Delphi and did a lot of coding on the app over time ... that led to the discovery of some very odd code expressions that are written as MUMPS expressions that actually compile in Delphi but don't work the same as they do in MUMPS!

     

    When I found the first one, it looked like perfectly good Dephi code, but it made no sense. After staring at it for quite a while, it seemed similar to some C++ short-hand expressions, but the semantics don't match in Pascal. Then I remembered that the guy who I believe wrote this code was mainly a MUMPS programmer, and then I read it as MUMPS expressions and VIOLA! It made perfect sense! Oddly, it compiles in Delphi, but would throw intermittent errors depending on the data it was dealing with. It was a total fluke that it ran correctly over 99% of the time. (I guessed the error rate was between 1:1000 and 1:10k, but it was hard to nail down.)

     

    I identified around 8 specific coding error patterns that occurred in over 100 places in the code. (The programmer used a lot of copy-and-paste techniques to save time, which made these snippets fairly easy to find once I knew what to look for.) A lot of them resulted in random data-dependent errors in code that had no error handling; they were also impossible to reproduce. I'd bet none of these have been fixed to this day.

     

    If someone knew where this code was, it could probably be exploited. 

     

     


  17. DataSnap is not available in the Community Edition. There are many alternatives. Two were mentioned above. Another one that I like is from TMS Software called XData; it's not free but they have a trial version available. mORMot is another one to check out: https://github.com/synopse/mORMot 

     

    I'm guessing that your Moodle thing is a separate back-end service that you're supposed to access via your self-made service. This is a very common scenario. Imagine that you want to have a web (client) app that saves photos somewhere. The front-end is kept simple, and it sends requests to your back-end where you could build an entire database that manages all of the photos yourself. A simpler approach would be to use something like Dropbox or Google Files (?) instead. Or even Google's FireBase. This would simplify your service a lot by letting it talk to the remote file service via its own API. It doesn't matter what it's implemented in -- the one you've been told to use is in Moodle, but so what? It's the API you're mainly interested in.


  18. On 2/23/2024 at 5:26 PM, Anders Melander said:

     

    This is something that real people with a narrow expertise who can think and dive into their own memory banks can answer. Google sucks at it.

     

    Unfortunately, StackOverflow has a policy where they don't allow questions like this that Google can't answer. They consider them "recommendations".


  19. On 2/24/2024 at 1:38 AM, Lars Fosdal said:

    @David Schwartz I assume there are paid services out there that offer such data.

    How many businesses are we talking about? If it is a limited number, it might be just as cheap to have someone google and register.

    around 950 for the particular batch I'm looking at initially.

×