-
Content Count
1237 -
Joined
-
Last visited
-
Days Won
25
Everything posted by David Schwartz
-
VirtualBox FTW! I've been using it for several years now (since 2017 or so) and have had very few problems with it. I run it on my Mac and do Delphi work inside of it on Win10.
-
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.
-
Delphi and "Use only memory safe languages"
David Schwartz replied to Die Holländer's topic in General Help
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). -
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.
-
Delphi and "Use only memory safe languages"
David Schwartz replied to Die Holländer's topic in General Help
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. -
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.
-
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".
-
around 950 for the particular batch I'm looking at initially.
-
Because I don't now where else to post it, and I'm guessing there are folks here who might know. Maybe I put it into the wrong section here. If so, feel free to move it.
-
As I said, " IntraWeb was introduced well over a decade ago". Meaning, it's MORE than a decade old. So you're saying it was introduced a year before Delphi ... ok. I still don't know of anybody using IW. So what does that tell you? Nothing. I've also never worked for a company that licensed anything but Delphi Pro for their workers, and they never used anything in the Enterprise Edition either. That's just been my personal experience. Nonetheless, all of these things are still being sold, which means SOME PEOPLE ARE USING THEM SOMEWHERE. I apologize for not finding places to work as a Delphi dev since 2000 that use any of them. As you say ... cheers.
-
Creating a recent folder location list in an INI file
David Schwartz replied to JohnLM's topic in Algorithms, Data Structures and Class Design
There's a version of Raize Components in GetIt, and they have an MRUCombobox that uses their INI files logic. You could look at that for some ideas. It's named something like Bonus KSVC 6.2.3 I work with INI files a lot, and there's a file I came across years ago named BigINI.pas that's got a bunch of higher-level functions added to the basic ones. I've added several things to it as well over the years. It makes using INI files a LOT easier! FWIW, the biggest PITA I've found with the basic INI file support is the fact that reading and writing uses different approaches, which is common in lots of places. I tried to add something to this to make it simpler, but it's not quite as robust as I'd like. What I'm referring to is this: you read a value from an INI file to a var somewhat like this: var myvar := myini.ReadString( 'section_name', 'the_var_name', 'the value' ); but you set it like this: myini.WriteString( 'section_name', 'the_var_name', myvar ); If you have a bunch of things to read and write, it's not very simple to copy one and paste the code and then edit it to do the opposite. I've been able to get ChatGPT to rewrite this code fairly reliably, but it's just a side-effect of using a language where assignments always are made from right to left. You can moderate that by creating some fancy methods, which is what I tried here at one time, but I'm not happy with the result. Treat them as experimental. 🙂 I've attached the file to this message. BigIni.pas -
Use of dynamic control names
David Schwartz replied to Bart Verbakel's topic in Algorithms, Data Structures and Class Design
If they are indeed "dynamic" controls -- ie, they're defined at run-time -- then the best way is to create an array of T or a TList<T> to contain them. If there are groups of them, then make a class or put them on a panel and make a list of the panels and iterate over the (known) controls on each panel. I find myself doing this relatively often for both components put on the form at design time as well as at run-time. -
I've used FastMM4 plenty of times, but I don't think I've used it with 10.4.2 at all. I keep getting this error message now: [dcc32 Error] E2201 Need imported data reference ($G) to access 'IsMultiThread' from unit 'FastMM4' I read the info on it, and nothing I tried worked. i didn't see this with 10.3.x or earlier versions. I've tried both FastMM 4992 and 4993, and get the same results when compiling. Is there a flag in the 10.4.2 IDE I need to set?
-
Ok, thanks. Good to know.
-
ummm ... you do know you can have more than one email address in your life, right? I know folks with 50 or 60 emails just on GMail (although I don't know how they keep track of them). I've got a ton of domains, and over a dozen of them have email set up. Why would you impose on somebody else like that? Just grab another email address from somewhere! Do you have a domain with web hosting? If so, you can easily go into your hosting control panel and set up another mailbox. EMBT is not going to match it up with the one you used to register your product even if its the same domain because ... how many people do you think have registered using a @gmail_com address??? Probably THOUSANDS! Just say'n. Anyway, the download and installtion takes way more time than activation.
-
One of the "features" of Delphi is the committment that the company has to backwards compatibility. Meaning, you could probably load up a Delphi 2 database app that uses BDE and have it recompiled and running fairly quickly, assuming it isn't using any 3rd-party components. I would not worry about anything built in 10.x that didn't work just fine in 10.x+n . If you had some code built for D6 or D7, then yes, you'd probably run into some problems, but even they wouldn't be very hard to get past -- again, assuming no 3rd-party components are involved. (I don't think you can load any components into the CE versions, so this shouldn't be a problem. However, I also can't imagine being constrained to work with ONLY the default components -- I had to do it at one place I worked, and it was a horrible PITA.)
-
Direct vs. Indirect access of service by a Client?
David Schwartz posted a topic in Network, Cloud and Web
I'm using TMS WEB core to build a web app, and it's talking with a dedicated REST-based service (built with XData). I have several back-end services that I'm using and the XData service interfaces with them itself. In most cases, it's also doing stuff that makes it more of a middle-tier app -- things that I simply don't want to do on the Client side. I see where TMS just came out with support for Google's Firebase using some DB-specific components in WEB Core that work on the Client side to connect directly to a Firebase DB remotely. In my mind, I tend to think of my back-end service as a class where I get and set things as needed, and I don't have to worry about how they're implemented or where they're stored. But putting logic in the Client that now knows these implementation details creates complications and dependencies that can affect future changes. I'm curious what others who've built some web apps think of the pros and cons of accessing back-end services directly from the Client app vs. through their dedicated service back-end? Do you mix it up, or prefer to hide everything behind your back-end service? -
Actually, I think it's far better than most job reqs I've seen that all look like they were copy-pasted from a book of generic job descriptions. I think it would help if it mentioned the application domain(s) that they're hiring for, along with some typical tasks they expect to accompany some of the skill requirements. (Apache, Linux, Windows ... beyond writing code ... sounds like an IT role.)
-
How do I know if the click is an actual user click ?
David Schwartz replied to dormky's topic in VCL
csUpdating is for use within components, and it's not just used for initialization. Using it to manage initialization in forms is ill-advised. There are three "levels" of initialization in forms: FormCreate, FormShow, and FormActivate. They occur at different times, and afford a lot of control over timing issues. If you want to see some really unpredictable timing issues with events, take a look at TTreeView and TListView controls. If you put some trace logic in the event handlers, you'll notice that several are called twice for every change. That can cause really strange things to happen if the handler does anything other than update a spot in the control. -
Direct vs. Indirect access of service by a Client?
David Schwartz replied to David Schwartz's topic in Network, Cloud and Web
I'm asking for YOUR opinion, and you just asked me some questions. YOUR opinion seems to be, "Unless I'm running something with the bursty traffic of a Superbowl ad, then I don't care." That's fine. Thanks. -
Direct vs. Indirect access of service by a Client?
David Schwartz replied to David Schwartz's topic in Network, Cloud and Web
Sorry, I'm not following you at all. This isn't an ad on the SuperBowl. It's a fairly nondescript membership-based service -- something like this forum, where the choice here might be whether the script talks directly to the service storing the data you're reading right now, or does it access it through a service (ie, a middle-tier) that might talk to different datastores and, for most purposes, introduces an unnoticeable delay? -
Direct vs. Indirect access of service by a Client?
David Schwartz replied to David Schwartz's topic in Network, Cloud and Web
@Fr0sT.Brutal I don't think you're understanding the gist of my question. I can't recall ever seeing anybody recommend that it's a Good Idea to write an app that connects directly to the IP:Port# of a back-end DB like, say, MySQL. Why? Because everybody who has been working in the industry for any length of time says it's a HUGE security risk to expose the local DB access port to the entire internet. There used to be this terrific, and inexpensive, DB management tool called SQLYog that had a proxy layer that completely insulated the front-end GUI from the back-end MySQL DB. (I think they expanded it to work with other DBs over time, but I only used it with MySQL.) You had to install a script on your server that it talked to via a secure connection so you didn't have to expose the MySQL port to the entire world. That was the only MySQL DB maintenance tool that was affordable that operated securely. It got bought up and now it's as expensive as the others. Did you write your own secure proxy layer for your remote DB applications? Given that you think it depends mainly on the number of API calls you need, I'm guessing you aren't really dealing with the underlying risks. It doesn't matter if you have just one or thousands of APIs -- all it takes is one a-hole and lots of time on his/her hands to swamp your server with direct requests to your IP:Port# in an effort to break into your back-end DB. It's not like most DBs don't have a well-known port# they're configured to use, right? MySQL uses port 3306 by default. How many apps have you built where you put the DB logic on the front-end and made port 3306 public on the back-end servier just so you didn't need to bother with any kind of API layer for security, eh? For most folks it's an all-or-nothing proposition -- you don't build it for just a few then throw it away as your API needs grow. And you don't take the easy way out and pretend it's not an issue until you get your system hacked and have to report it to your users and the authorities as a breech. In this case, if you have a web app (as opposed to a typical client/server app that runs on a intranet LAN), it's probably designed to access most logic through your own back-end service. Even if the API itself is published (and many public services are; eg., Amazon and Google, among many others), the security is set up so nobody knows how the services themselves are implemented. It's like OOP -- you've got some "encapsulation" going on that hides the underlying implementation, with all of the corresponding benefits. One of the biggest consumers of such public APIs is Zapier, and they don't seem at all concerned with the quantity of calls each of their services might support. But if you DO have a dedicated service layer on the back-end, and then decide to implement some UI features that access something like Firebase directly from the front-end, you've now exposed an implementation detail to the world that can be easily detected that people might try to hack. Sure, it's more secure than just a raw IP:Port#, but ... I'm wondering how many people who've built apps partitioned this way think it's a risk or not. Are they inclined to hide everything behind their own services API? Or add-on UI services that expose some of their back-end service providers directly? -
what options exist to access Firebase from a VCL app?
-
In my limited experience with APIs and REST interfaces, it seems the API says whether it's a GET, POST, or some other HTTP request type, regardless if it follows typical REST protocols. Recently I had an encounter with a REST interface that's not just a POST request (due to the size of the payload) but it also allows optional querystring parameters on the URL. It sends data back in a RESTResponse packet. It took me quite a while to figure this out since it's not even clearly documented. Whaddaydo?
-
There are plenty of Delphi examples that could be cited as guides. Google this: "how to query a rest api using delphi" Even asking ChatGPT can elicit a decent response