Jump to content

David Schwartz

Members
  • Content Count

    1237
  • Joined

  • Last visited

  • Days Won

    25

Everything posted by David Schwartz

  1. David Schwartz

    Anon methods passed as event handlers?

    I think you totally missed my point. As I mentioned, at one time, both automatic reference counting and generics were "impossible", due to "pesky facts". Whatever happened to those "pesky facts", eh? They may not yield to "attitudes" per se, but they do yield to people up the Management chain who have vision and determination to see the value of certain things over the long-haul. I don't think there's anybody in Embt right now who has enough vision or determination to change the course of the Delphi language much over the foreseeable future. Especially when there are so many willing and able-bodied defenders of the status quo around. In another 10 years, most of us are going to be gone -- physically, mentally, or just because we retired. Then what?
  2. David Schwartz

    Anon methods passed as event handlers?

    In 1961, when Pres. Kennedy announced that mankind would go to the moon by the end of the decade, there wasn't a single person alive who knew how to do it. When Henry Ford told his engineers he wanted an 8-cylinder engine, there was nobody alive who believed it could be done. And here you are redoubling your efforts to explain to me in ridiculous detail why the simple thing I want to see possible at the source code level is impossible to do. The purpose of the compiler is to hide complexities like this from the user. Automatic reference counting wasn't viable ... until it was. Generics weren't considered viable ... until they were. There are so many things that people thought would be "nice to have" but weren't considered viable, and at the time there were perfectly valid technical arguments that were made about why they weren't either practical or even possible. Until they were. A lot of contemporary programming languages support stuff that Delphi could support, but there needs to be the willingness on the part of the folks who maintain the Delphi compiler to actually embrace them. Delphi was revolutionary when it launched, but within a few years, it got stale, and the language has only improved slightly (IMO) in ways designed to appease the marketplace just to keep people from bailing out to other platforms entirely. C# has so many cool language features that I doubt we'll ever see in Delphi. I don't know why, because adding new language features to a product that's supported by pretty hefty annual fees makes a lot more sense than adding features to a product that's mostly funded by other product sales (as most of Microsoft's language products are). I mean, what incentive does Microsoft have to keep adding new features to a language that generates relatively small revenues? For one thing, you can argue customer lock-in. For another, newbies want to hitch their wagon to technology that's more leading-edge rather than stuff their parents or grandparents used. I'm really not interested in the technical reasons why this suggestion isn't possible today. Just like I'm not interested in justifications why you can't use strings in case statements in Delphi while most other languages today allow it. There has to be a willingness on the part of the vendor to add these sorts of upgrades to the language instead of defending their absence, which is the normal case with Delphi. You're just defending the status quo. BTW, C++ was introduced about 10 years before Delphi. The first ANSI standards effort for C++ started about the same time Delphi was introduced. And now they just approved the 3rd iteration of the C++ standard, with work progressing on the 4th iteration. Meanwhile, Delphi has hardly had anything new added since the first C++ standard was released. People pay Embarcadero a lot of money every year to maintain and upgrade Delphi. The backlog of bugs keeps increasing, and the language enhancements progress at a snail's pace. What are we paying for exactly? Most of what we get are lots of technical arguments about why this or that language enhancement is not worth considering, while job reqs for Delphi dwindle and vendors want to hire people with experience using the latest language features that aren't even on Delphi's radar. Why in the world would anybody want to choose Delphi to develop a new product with a 10-15 year life span today? All the jobs I find advertised are for maintaining legacy apps. Where's the NEW product development happening with Delphi? Why would anybody want to hitch their wagon to an old, stale technology that's so far behind the language technology curve?
  3. David Schwartz

    Anon methods passed as event handlers?

    Rudy, I get what you're saying, but that's not what I mean. I meant that it should be possible to have a syntactic construct that would allow you to define an inline anon method that works in all cases, as opposed to working for some but not others. If it means adding "of object" to the signature or whatever (plus maybe something else), so be it. Right now it seems as arbitrary as, say, allowing you to use procedures but not functions, or vice versa.
  4. David Schwartz

    Anon methods passed as event handlers?

    FWIW, I found this on SO: This is not possible. You have to make the event handler be a method type rather than an anonymous method. You'll need to wrap your anonymous method in a method. Either an instance method (of a record or a class), or a class method. For instance: https://stackoverflow.com/questions/8025481/vcl-events-with-anonymous-methods-what-do-you-think-about-this-implementation https://stackoverflow.com/questions/11491593/tproctobject-to-tnotifyevent
  5. David Schwartz

    Anon methods passed as event handlers?

    So can you add the Self param explicitly? Or is there just no way to do it? I'd think that this might work, but it doesn't. FScript.AfterExecute := procedure (Sender: TObject; SQL: string) of object begin // end;
  6. David Schwartz

    Wow, first time using repeat ... until

    I was referring to for, while...do, and repeat...until.
  7. David Schwartz

    Constructors + Destructors in class helpers?

    Thanks, guys. After some trial-and-error, I realized a helper won't do what I was wanting it to do. So instead I created a wrapper class because I needed to add data fields as well as methods to it. That seemed easier than dealing with a derived object that's part of 3rd-party lib.
  8. David Schwartz

    FireDac PostgreSQL and TBatchMove

    no, sorry.
  9. David Schwartz

    FireDac PostgreSQL and TBatchMove

    ExtendedMetaData slows things WAAAAAAAAAAYYYYYYYYYYYYY down! Don't enable it unless you absolutely need it! (I'm using PgDAC components, and we traced this into an auto-generated second query that is issued to the server after every query to get metadata for the previous query, and it runs slower than molasses in winter! We couldn't figure out why, but we just set the component to generate V2 queries rather than V3 queries to always suppress the metadata inquiry. Otherwise, you have to do it on each query you issue. But again, that's PgDAC.)
  10. David Schwartz

    Any advice when to use FileExists?

    Historically speaking, the old DOS FAT file system was notoriously inefficient when it came to looking up filenames. The original FAT directory segments held something like 63 x 8.3 filenames and the last entry was a pointer to the next segment. Each time you ask for a file, the FAT file system would begin a linear search at the first directory segment and scan through each one to the very end of the list before it knew if it existed or not. It was always faster to get a list of files first into a memory buffer, sort it, then search that first before probing the file system. But the real solution laid in splitting things up so you didn't have more than a few directory segments anywhere. That usually led to something where you had two directory levels: one that was simply A to Z, and the next that contained folders or files that begin with that letter. Sometimes it would help a lot to go down and additional level. Also, FAT directory segments were filled from front-to-back. If a file was deleted, the slot for it would be cleared. A new filename added to a folder would take the first available slot. So putting thousands of files ('n') into a FAT-based folder would take on average O(n/2) tests for filename equality. Going from front to back probing with names, whether it was an ordered or unordered folder, would take the same amount of time. Introduction of long filenames added further delays if you used the long filenames. I'm not sure what FAT32 did to improve this, if anything. Windows introduced caching of directory segments that sped things up considerably. From what I understand, NTFS introduced something closer to what Unix does, and resolved this inefficiency somewhat, although I never did anything that pushed the limits of an NTFS-based file system the way I used to do with old FAT-based file systems. With faster CPUs and more extensive caching in Windows, the problem seemed to fade out. Part of the solution was to use FindFirst/FindNext, even if this meant you built a list in memory to search against before asking the file system for anything.
  11. David Schwartz

    Efficient list box items with Frames

    I would def not use a TListbox for that purpose. Check out TFlowPanel or TGridPanel. I think one of them would be best suited for what you're looking for. Maybe on a TScrollPanel. https://stackoverflow.com/questions/3254026/how-can-i-scroll-the-content-of-a-tflowpanel I don't know off-hand if I'd use something derived from a TFrame or TPanel for the inner blocks, but I'd probably try the TPanel first, just because TFrames can be a PITA to deal with at design time. There's also this: https://torry.net/pages.php?s=79 Look for: "DictaSoft Layout Pack v.1.0"
  12. David Schwartz

    Any advice when to use FileExists?

    The Windows file system segments get cached. The first time you call FileExists, it might take a little bit of time to load the segment from disk if it's not cached already. But after that it would run very fast unless you loaded so much stuff to memory in between that it got flushed out of cache. It's not something I'd even worry about. In fact, unless your files are really huge relative to free memory, they'd be cached as well. I don't know if the underlying Windows logic would load them in segment-sized buffers (4k or whatever) or try to suck the entire file into memory at once if it detects that there's sufficient free memory. Windows has gotten pretty darn good at managing its virtual memory. Way back in DOS days, we worried about this stuff. But when you've got gigabytes of free memory and you're loading up files smaller than 1MB or so, it's mostly irrelevant. I've got an app I built a few months ago that loads up all of the *.pas and *.dfm files it finds in an entire file tree ... several hundreds of them. Some are over a MB in size, but the average size is around 80KB. It takes less than a second to load them all from my SSD into memory streams and attach them to the .Data property on a TTreeview. Then it takes 30 seconds or so to parse them all looking for whatever stuff I want using regular expressions. RE's aren't the fastest things to use for parsing data; they're just a heck of lot easier to use than building a dedicated parser. Needless to say, as far as I can tell, the vast majority of the run-time overhead is taken up in the memory manager allocating new objects, copying data identified by the RE parser into them, and adding them into other containers. And in most cases, the biggest delays are caused by the VCL UI components, usually because I failed to call DisableControls on visual components while I'm loading them up. When I do that, UI progress updates are STILL causing the lion's share of processing delays! I mean, I can cut my parsing time in half if I don't want to tell the user what's going on, but that's poor UX design. Most people would rather be kept updated on long-running processes than having them performed in the dark with no idea how long they should take. I cannot imagine how old and slow of a computer you'd have to be running where calls to FileExists would take a noticeable amount of overhead. Maybe a 400MHz Celeron with 256KB of RAM and a 20GB HDD or so. We're talking something from the late 90's. I know there are small SBCs like that are still being used for process-control apps, but even Raspberry Pi's have more computing power than that! I'd urge you to focus on the efficiency of the value-add you're providing, not wasting time second-guessing the imagined inefficiencies of the OS. Get your program working, then look at where it's spending the most time. Most likely, about 98% of the actual execution time is going to be spent in your code or in the UI (eg, VCL). Not the OS interfaces -- unless your app is doing a HUGE amount of interaction with the file system. Even DBMS systems exhibit amazingly low file system overhead most of the time.
  13. David Schwartz

    Any advice when to use FileExists?

    If you're worried about the parsing taking a relatively long time, then simply create a TMemoryStream and do LoadFromFile and parse that instead
  14. David Schwartz

    Wow, first time using repeat ... until

    That's true. I guess I spoke too hastily. That said, I rarely use repeat-until in Delphi, and I wish the for loop was more like C's for loop. That's it. 🙂
  15. David Schwartz

    Wow, first time using repeat ... until

    I don't really care what it's called. Every language has its quirks. Why does Pascal have three distinct forms of loops? Seems like overkill. And each one has its own limitations. What would you have called it? I'd nominate either "loop" or "repeat" -- but this is ONLY for the C/C++ language.
  16. David Schwartz

    Wow, first time using repeat ... until

    Sorry I'm not sure what's your point. I like the way the for loop is structured in C/C++ because all three relevant state mechanisms are there: the initializer; the condition to continue or stop; and the iterator used at the end of the loop. Perhaps it's inconsistent syntactically, but I find it much more consistent in terms of how I think of loops working, since it completely controls the statement or block following it. I can't tell you how many times I forget to put the iterator at the bottom of the loop block in Delphi. It's pretty damn obvious when it's missing in C/C++ FOR statements, and even the compiler can flag it for you. But in Delphi, you get no help from the compiler, and it's not even obvious something might be missing just by looking at the code. And if you happen to put it in the wrong place in the loop block, it can cause you no end of headaches. The C/C++ approach is much safer and easier to see when it's missing or wrong. There's also the problem that the Delphi approach requires you to reference a loop var within the block that may otherwise not even be needed.
  17. David Schwartz

    Wow, first time using repeat ... until

    Back to the original topic regarding repeat ... until: I use them very rarely myself. I really miss the for statement from C/C++ in Delphi, because it lets you specify the initial condition as well as the test and incrementor all in the same line. The problem with most loops is you need to do something first to "prime the pump" so to speak, before you can get the while or repeat loop running. A classic one is iterating through the results of a DB query: qry.Open; . . . qry.First(); while not qry.EOF do begin . . . qry.Next(); end; In C/C++ that could be done as follows: for (qry.Open; not qry.EOF; qry.Next) { . . . } I think this is much nicer.
  18. David Schwartz

    Wow, first time using repeat ... until

    It's still GPF in my mind! I have no idea when they renamed it. IIRC, GPFs were frequently accompanied by BSODs, which still happen every now and then. (I'll let someone ask what they are... )
  19. That's certainly true. What I had in mind was DI performed through Constructor Injection as well as Getter/Setter (or Property) Injection, rather than the inheritance type of Interface usage. Mark Seeman talks about the inevitable tendency to turn multiple parameters passed to a class via CI into a Parameter pattern that evolves to a standalone record/struct or class, so he suggests short-circuiting the inevitable by using a Facade pattern to pass one or more parameters through a separate object for CI. This could also be managed with an Interface. Getter / Setter / Property injection might not fare so easily, unless you used this approach to pass in a Facade class with lots of values. Usually, they're one-to-one, however.
  20. I seem to recall seeing someone post about a tool they wrote that converts components dropped on a form into equivalent code that creates the same components at runtime, and possibly vice versa. IIRC, the context was something talking about the automated testability of forms, and/or avoiding problems with source control tools. I'd like to get hold of that tool for some testing.
  21. David Schwartz

    Tool to convert form components to run-time and vice-versa

    I'm aware of GExperts, but I thought it was something else.
  22. It wasn't my choice, and I personally don't care. It's just what I've been given to work with. Upper Management makes all sorts of decisions regardless of my input, for reasons that are opaque to me, and I've learned it's safer to just accept their decisions.
  23. Your example highlights the fallacy of your assertion. In fact, inheritance locks you into whatever resources are required by the parent class! In this case, Indy. FTP is a very generic thing. Why inherit from a specific concrete implementation that locks you into it's view of the world for ever and ever? I think a far better approach would be to "inherit" from an abstract base class (a.k.a. "interface") that would allow the use of virtually ANYTHING that supports generic FTP features, including the one you happen to prefer today. But at that point, you're about 50/50 whether that approach is better than using composition (HAS-A) to include an API that offers the same abstract interface, possibly as a drop-on-the-form component. Unless your goal is creating a bigger, better, faster, or more specialized version of the base class, then inheritance of a non-abstract base is silly. Without multiple inheritance, you're locked into specializing or expanding a single concrete base class anyway. So if you're building a class that EMPLOYS FTP, for example, but IS NOT INTENDED to BE a "better" FTP service, then inheritance is clearly a very poor choice. And inheriting from an abstract class presented as an Interface is simply a way of mixing-in a single type's namespace with your component's namespace. It's effectively just "anonymous composition" because you simply refer to the methods and properties as if they're part of your class, without having to refer to the name of the object containing them. Finally, you can do dependency injection just as easily without interfaces.
  24. Mida is a tool that was written to simplify translating VCL apps to run under Firemonkey. It evolved to the point where V5.x Studio edition started supporting arbitrary rewriting of components without requiring VCL->FMX. I'm looking at using it to translate a bunch of VCL apps that use Allround Automation's DOA Oracle components to use PgDAC components instead. It looks like it should do the trick, but it requires a file in INI format that isn't clearly documented. They have some examples for BDE, FD, and a couple others. But I can't find any detailed explanation of how to go about creating the .mida file for something else, or even how to set one up. Are they built entirely by hand? Or does the Studio version let you build them somehow? They're a little slow on responding to support requests; the videos on YouTube haven't been updated since V2 was released; and I can't find any help files or documentation anywhere. (I have a licensed version of V5.6 Studio.) So I thought I'd ask here and see if anybody has any experience they can share.
  25. perhaps. But we've got to migrate to one or the other, regardless. Also, FD uses a DLL for Postgres, while PgDAC goes direct.
×