Jump to content

David Schwartz

  • Content Count

  • Joined

  • Last visited

  • Days Won


David Schwartz last won the day on April 13

David Schwartz had the most liked content!

Community Reputation

169 Excellent

Technical Information

  • Delphi-Version
    Delphi 10.4 Sydney

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. David Schwartz

    swagger help needed

    Just FYI, I'm not "still on" any particular version of swagger. The project I _was_ on had swagger info published that's generated from Microsoft tools that are in widespread use, and that code itself reports that it was V2.0. I have sampled a bunch of swagger specs I've found around the internet, and I've found very few that are V3.0. I don't know who produces these or how, but if most are being generated by MS tools, then consider it's MS themselves that's responsible for this disparity. Certainly nothing I'm connected to. (I'm not on that project any more, and anyway they had told me not to even use Delphi. So at this point it's just a curiosity.) If MS isn't supporting V3.0, then I'm not sure who's going to use it if it's really that hard to parse.
  2. You might want to look at TMS WebCore running on VSC.
  3. David Schwartz

    swagger help needed

    The API I was originally working with is internal, but I've tried reading a number of ones I've found around the internet. There are tons of them. I'm not understanding why java is needed to build something to consume JSON text, build some internal tables, then spit out Delphi classes. From playing with the earlier referenced code, the trickiest part lies in two areas: 1) recognizing isomorphic structures (ie, classes with the exact same data members) and combining them into a single definition; and 2) if you allow selecting only certain APIs or groups, then optionally being able to emit only dependent variable and class definitions and skip everything else. The first step is needed to avoid having a bunch of identical classes defined just because the Swagger code defined them and didn't name them, but the parser gave them all unique default names; or they were named in the Swagger text and all were given different unique names for no particular reason. (I saw a situation recently where a common error return structure generated over 50 identical classes where each one had been given a different name. It's completely unnecessary, and simply requires that the structure of these be recognized as identical and a common base class generated that's used for all references. Worst-case, it would be used as the base class for child classes derived from it. I'd lean towards leaving them all referring to the common base class, then maybe add derived classes to distinguise different error returns, or whatever makes sense in the context. A flag to give you a choice might be a nice option.) There's also the matter of how the emitted classes are ordered. The original code sorted them alphabetically, which might not work for Delphi. If you remove the sorting, then they are emitted in the order they're encountered in the Swagger spec, which may not translate into proper ordering for Delphi either. So internally, it needs to have a way of flagging dependencies and using that to emit code in "layers", or at least in an order where dependent types, vars and classes get defined before they're referenced.
  4. David Schwartz

    swagger help needed

    I don't even use Java, so this isn't much help for me. This thing from my original post: https://github.com/marcelojaloto/SwagDoc and related updates already gets us into the ballpark. The main problem is that it assumes the use of the MVC framework here: https://github.com/danieleteti/delphimvcframework Instead of calling the mvc framework, it needs callbacks or another way to handle data as its parsed. I guess JSON can be a little ambiguous in some cases, which makes it hard to parse?
  5. David Schwartz

    Download Images from a URL

    The FNC components are intended to save you the most EXPENSIVE time -- YOUR PROGRAMMING TIME. If you don't value your time, then don't bother using them. You could also look at the source code and see what they're calling "under the hood" to investigate if there may be a more efficient approach on one platform or another. There may well be. But so what? In order to get a set of components that work and act the same on all platforms, they've needed to implement certain abstractions that are necessarily going to have a cost. That said, the time of the data transfers in this instance will, in most cases, swamp out the abstraction logic, unless they're doing unnecessary data copies. The truth is, most people do not bother to optimize their images in the first place. So you're looking in the wrong place for large speed improvements! Do you have any idea how much bandwidth is wasted by people who take 16 MPixel images then send them to their friends to look at in a 1" x 1" box on their cell phone? A 16 MP image is like a full HD screen in resolution; the 1" x 1" box on the cell phone is under 10kb for an image that most people couldn't see any difference between the two. You need to optimize the images BEFORE they're downloaded to get the most sigificant improvement in DL speeds! Because there's nothing you can do to move an 8MB image as if it's only 10KB in size.
  6. David Schwartz

    Event Listeners Delphi <-> Web

    This problem reminds me of a system I had to analyze in college for an Information Analysis course that involved a new meal ticketing system being set up in the cafeterias around campus. They wanted people to be able to buy a meal ticket at any of the cafeterias, right there in line. So Joe would buy a ticket, get it scanned, and go in to have lunch; but his buddy Bob would come by just as he was entering and say "Hey, Joe!" and they'd shake hands and the ticket would invisibly move from Joe to Bob. Then Bob would go to another cafeteria and use it again. They knew there was a problem, and some said it was a bug in the software. But that wasn't it. Joe got what he paid for, but Bob got a free meal. This is a very old and common problem involving a state machine that has nothing to do with Delphi, web apps, firing events, QR codes, or how many gaming centers a company may or may not have. And it's not so much a matter of programming as it is recognizing the nature of the problem and the best approach to a solution. First, I suggest you rewrite the description, leaving out all of the implementation details. They may be causing you confusion. Express it as a list of "current_state -> event -> next_state" rules. Second, refresh your knowledge of protocols and state machines, and review "protocol sequence diagrams" and maybe "state transition diagrams". (There are certainly tools that let you do this, but a pencil and paper are probably much quicker.) Third, go read some of the RFCs for email handling on the internet from back in the 70s and 80s. The internet was literally designed to survive a nuclear attack that took out random data centers, and the data packets (eg, email messages) would still find their way to their destination in a reasonable time-frame. (Results may depend on one's definition of "reasonable".) What you're trying to model here isn't much different than how basic email delivery is managed. Data moving at 150 baud on a dial-up line is pretty damn slow by today's standards; but sending out a 64 byte packet (probably overkill for this) will still make it 10 miles across town way faster than any human can move. Which leads us to the forth and final thing to do: write up the Terms and Conditions that apply to all kinds of tickets and how they can be used in this network. Starting with the misnomer that "customer buys a ticket" equals "days of free [access]". That's like saying if you buy a bus pass for a week then you get a week of "free rides". No! If you don't have that pass with you and you're caught, it's going to be even MORE expensive than what you already paid, right? (This was the source of the problems with the meal ticketing system I analyzed. They were selling tickets at the door, but the data was entered manually some hours later, but before the next meal. So the tickets could be used any number of times between when they were purchased and when they got entered into the system. They had to change the rules about when tickets could be purchased, and ensure the data was entered into the system before they could be used.) Terminology is important when it comes to design. In this case, the system might actually support "free passes". And if a center is stuffed to the gills with customers who PAID for tickets, you might want to BLOCK those with "free passes" from coming in, or just during certain times. See the distinction?
  7. David Schwartz

    caFree & ,Free??

    Marco is enumerating a few ways of approaching a common situation. Which you choose is up to you, based in large part on surrounding contextual stuff you might know about in that situation that someone else would not. You're asking something like, "What is the best way to introduce a person to another person in terms of what you say?" Are they two friends of yours? Are they strangers to you? Is one a dignitary? Is one the opposite sex and you have to follow certain rules? Are they possibly antagonistic towards each other (eg, a drug dealer vs. a police officer)? Is one a family member or someone you are concerned about for some reason? Do you have an agenda in introducing them? You seem to be asking for something to say that will work in 100% of situations. It's not possible without sometimes sounding like an idiot. You need to adapt your interactions to the situation at hand, just like you would employ different water management policies in a rain forest as opposed to a desert, although you'd use the same tools in both cases.
  8. David Schwartz

    Learning Delphi

    I just made a list of some stuff off the top of my head. These are all things I run into pretty regularly, so they're not very mysterious. It would be instructive to make a list of all of the different ways the following three common idioms are expressed by different programmers in different projects, and how many variations can be found within the same large project: * Logic that would use a Case with a string discriminant if the language supported it * Ways of mapping Enums or regular consts (both numbers and strings) at run-time to some kind of display string that's more readable, including how they're initialized * Form interactions (we could be talking 2-3 DOZEN here!). Variations would include these idioms for both getting and setting values in the form: -- auto-create vs. on-the-fly creation and destruction -- constructor injection -- requires overloading Create that hides default ctor -- property injection -- method injection -- direct access of members (UGH!) -- forms that manage Add / Edit in the same form vs. one for each -- embedded selection popups on fields: read-only vs. ability to add something new (requires another form) -- field validation (before vs. after exiting the form) -- Hiding / Closing / Freeing the form Actually, I bet a whole book could be written on "Form Interactions in Delphi". It's hard to argue there's a "right way" or even a "best way" to do it, but there certainly are a LOT of ways!
  9. David Schwartz

    caFree & ,Free??

    This is a REALLY BAD APPROACH. I don't care if you use with or not. But you don't create an object then say "with <object> do" and then refer to the object in a Finally to free it AFTER you ALREADY FREED the object inside of the Try block! But you don't know at this point because you already (and invisibly) delegated the form's lifetime to the form itself. BAAAAAAADDDDDD! Here's what you could use instead: // Do NOT override the Create to inject parameters into the form unless they're actually required. with TMyForm.Create(self_or_NIL); try // Forms rarely if ever need Constructor injection. The most common misuse is passing DB-related details into // forms that are designed to only work with one table or one specific query or stored proc. It's hardwired. // It just needs a key to do a lookup. And don't rely on the "current record" in another form! // Instead, use PROPERTY INJECTION to initialize properties in TMyForm here, eg., by passing in a key. // And yes, TMyForm is an OBJECT and you should access things inside of it using PROPERTIES! // The setter for this property could trigger a DB lookup that initializes other fields on the form. UserName := 'Fred Flintstone'; . . . // now show the form, and do NOT delegate lifetime to the form if (ShowModal = mrOK) then // requires setting the Action param to caClose NOT caFree!!! begin // now retrieve values from properties in the form, if needed. // note that you can't do this if you use caFree since it's DESTROYED at this point! // which is why it's a Bad Idea to delegate lifetime to the form. // You're using a with statement here, so you can't set it to nil. And even if you weren't, // there's no way to know that the form killed itself. // Unfortunately, it will work often enough that you'll think the occasional exception is for other reasons. Result := PhoneNum; . . . end; finally // NOW Free the form instance Free; end; This is a nice, solid pattern that will serve you well in ALL form interactions. The only excuse not to use it (and not use PROPERTIES inside of the form) is if you're being LAZY. The use of with can be debated until the cows come home and it boils down to a religious debate; but at the end of the day it's really a personal preference as far as I'm concerned. But the way you've done it is obviously error-prone and not something you'd want to do everywhere (for consistency). See my CodeRage 9 talk for more on this topic: https://www.youtube.com/watch?v=JgOhg2GbydQ
  10. David Schwartz

    Learning Delphi

    Right out of school ... it will depend what they were exposed to in school. They probably understand OOP and OOD, but may not have much experience with strongly-typed languages like C/C++ and Pascal/Delphi. To me, after 40 years, most imperative languages all look the same, except for added things for stuff like vectors, parallelism, and more esoteric stuff that all tend to be language-specific. The latest feature that most languages are adopting is the use of "attributes" on classes and class members. I don't know how Delphi's stack up against any others, but it may be worth discussing. Other than that, what I'd call the "dynamics" are going to be a big part of what can hang them up. For instance, Delphi has added some interesting features to the language like for...in that make using various kinds of containers a lot easier. But there are things missing from Delphi that make it impossible to use some of these newer features at times. For...in is great unless you need to refer to the index or position of the selected item in the list, for example. The lack of a trinary operator means there are lots of if...then...else statements that could be collapsed into a much simpler trinary expression. There's the IfThen method, but it evaluates both arguments before choosing one, which makes it useless when trying to avoid referencing null pointers. Most contemporary languages accomodate both of these things today, so it might seem confusing in that respect. (Delphi may support it in an upcoming release as part of NULL expressions, but a trinary operator could have been introduced in the languge way back that simplified it forever.) The RTL has been extended using class helpers to mirror a lot of stuff commonly found in C# today. Class helpers seem like a hack to me, but they do let you introduce new methods into a class without having to either modify the class itself or subclass it. Unfortunately, they're not inheritable, which seems really strange to me (and probalby newcomers as well). Most contemporary languages also support case statements that take strings as discriminant variables, but not Delphi. This gives rise to maybe a dozen different ways people work-around this missing language feature that's only missing for little more than "religious" reasons. Initialization of arrays, lists, and objects in Delphi is something that isn't often consistently applied within and across projects, so make some clear recommendations. (Good Idea for a Coding Style document.) In particular, if you have a list of Enums, there's a common practice of prefixing them with a couple of letters so you know what class they belong to. This prevents simple use of RTTI to get a string representation of their name to display at run-time. So you need a second array of names and a lookup function for that purpose, although I've seen slightly more elegant ways of doing it that escape my mind at the moment. (To me this sort of variable-name-to-string-name mapping should be a fundamental language feature of every programming language ever written. In practice, few if any offer anything at all.) This stuff can be really confusing to people familiar with what other contemporary languages offer in their place. So I'd say give them a lot of "bread-and-butter" type code to write and do a lot of code reviews to suggest alternate ways of expressing things to expand their understanding of the language and RTL. If you're having them build UI-based apps, try to instill some good coding practices, like avoiding putting logic into Event handler methods. It's so easy to do, right? For example, the presence of an Add and Edit button on a form might lead to two almost identical methods, one of which might initialize stuff from one set of vars while the other will initialize with constants. And to allow a "Cancel" button, you probably need to track whether you're in Add or Edit mode. (Forms that use DB-aware controls can handle this directly.) One thing that I personally find quite ridiculous is the fact that most Delphi programmers don't treat interfacing with forms the same way as other objects. For reasons going back to Delphi 1, Delphi allows the programmer to reach directly into forms and fiddle with local variables and even fields from methods inside of the client forms (which are bona fide objects!) using with them, where nobody in their right mind would do the same thing with normal objects. I see very few Delphi apps that do this consistently and what I'd say is "correctly". Again, I think this gets into more of a "religious" debate, but if there's not a lot of consistency in how it's done in your projects, a new programmer is going to naturally ask "WHY?" and be rightfully confused over something that really has no excuse other than the programmers were lazy. Finally, keep on the lookout for use / abuse of global variables. As far as learning the language itself goes, I'd say any old Delphi book from D4 onwards can be used as a guide for most things, except the screenshots of the IDE. Newer versions have more methods in older (ie, "classic") objects than are found in older books, but what's there is pretty much all still 100% valid. I'd also be tempted to give them some exercises to learn all they can about TStringList. It has always been one of the objects in the RTL that I've used the most over time, and they seem to keep adding new functions to it with every Delphi release. This is what comes to mind in a few minutes. There's probably a lot more.
  11. David Schwartz

    Learning Delphi

    Of course, there's also Marco's latest book. And even stuff like old Delphi 3 and 4 books would work for covering the basics (just don't look at the screen-shots!). Are they new to programming? Or just new to Delphi?
  12. David Schwartz

    Copy a form in a project?

    I'm taking an approach where I'm building something piece by piece where I do some work with a form until I get where I want to be, then I want to clone it and modify it for the next step. So each step is a separate form. This is simply for development purposes, and I don't want separate projects. I'm curious if there's an easy way to "smart copy" a form? Right now it seems you have to "Save As..." a new form name, then rename the form and its class, then add the previous form back into the project. Are there any wizards that might add a "Copy form..." or "Clone form..." option to the Project Manager's right-click on a form name?
  13. David Schwartz

    How to gracefully get rid of the use of dictionaries?

    I saw where it ended up, although I didn't look all that closely at the details. Just chiming in with my thoughts about the use of TDictionary in the first place, AND the use of code to explain code.
  14. David Schwartz

    How to gracefully get rid of the use of dictionaries?

    Code is supposed to reflect your design goals. I get nervous whenever someone tries explaining their design with code. I still don't know what you're trying to accomplish here other than change your code somehow. Are you familiar with Einstein's famous quote: "You cannot solve a problem at the same level of logic used to create it"? You showed us some code, assert there's a problem, then ask how to rewrite the code to solve this supposed problem without explaining a larger context. Several people made guesses based on assumptions they all had to make, but none of us really know for sure what the problem really is. I mean ... I do not understand why the dictionaries are there in the first place either.