Jump to content

David Schwartz

Members
  • Content Count

    1191
  • Joined

  • Last visited

  • Days Won

    24

Everything posted by David Schwartz

  1. David Schwartz

    CreateProcess[A] only returns Chinese

    Ok, one more question. What's the difference between using CreateProcess, CreateProcessA, and CreateProcessW if the internal process being spawned may or may not be producing data in the expected format? (Ansi vs. Unicode) Why would you choose one or the other if it depends more on the ReadFile() ?
  2. David Schwartz

    CreateProcess[A] only returns Chinese

    Remy, this is an awesome explanation. To summarize: there's an impedance mismatch of sorts between the command being run and the data it's spitting out vs. the rest of the processing pipeline. The command I was testing is the simple "dir c:\" command. It's running on Windows 7, so I'm guessing that everything outside this process is all Unicode. Why is a mismatch arising? Just out of curiosity, what's the dominating factor here? The app (command.exe); the program (dir c:\); the ReadFile() function; or the type of the storage array used? Or does everything have to be in alignment / agreement? (I did study the code before posting here, and it is a bit mind-numbing in this case.) What's not quite fully distilled for me is this; it sounds like the "data pipeline" around the CreateProcess call (including all of the various handlers) may need to be tailored for EITHER Ansi OR Unicode. Is this true? Or is there a way to handle both? I guess it's irrelevant tho, because I plan to use this to run exactly one program (Ora2Pg, which is built on top of a Perl platform). That said, what's the simplest way to deal with this issue?
  3. David Schwartz

    libpq.dll for FireDAC?

    I cannot seem to find a libpq.dll for Postgres that works with FireDAC in D10.2.3. Any suggestions on where to get a copy? NOTE: Please don't say to ask Google! I've pulled down five different versions that all have different datetime stamps and are supposedly 32-bit versions, but none of them work! If you have one that DOES work, where can I get a copy?
  4. David Schwartz

    How to replace whole words in a string

    I use the RegExpr library from years back. It's great. Very easy to set up patterns to detect words.
  5. There used to be a library named Hipparchus that used Voronoi maps to accomplish this sort of thing. Microsoft bought Hipparchus, converted it to C# (from Fortran and C) and embedded it into SQL Server as it's GIS engine. These guys published an article in Dr. Dobb's back in 1992 or so that explained it very well. They also published c code and some tools in conjunction with that article. But they also sold the Hipparchus library commercially. It was a lot more involved than what the Dr. Dobb's article did. Since MS bought them out, they started an open-source effort to do similar stuff, but I haven't seen any updates in quite a while. I'd love to get hold of a copy of their library with the source code, if anybody might know of a copy sitting on a shelf somewhere. Unfortunately, once they sold to MS, the company had to pull their stuff off the market. I learned about the sale about a month too late. 😞 Essentially, there's one app that preprocesses a sampling of the data and creates a voronoi map. Then all of the points are translated from lat/lon to vectors based on the centroid of a voronoi cell where each point is a tuple <cos(p), offset>. As it happens, all of the math can then be done with simple 16-bit signed integer calculations, which makes looking for common types of things, like nearest-neighbor clusters in a set of points, extremely quick. But, if you have access to MS SQL Server since 2010 or so, I believe this logic is included in their GIS package.
  6. David Schwartz

    How to switch condition position?

    Rudy said: I think this order is guaranteed, but I would not really count on it. There's a compiler switch that overrides this, so it's not really "guaranteed".
  7. David Schwartz

    How to switch condition position?

    There's always the IfThen function. Result := IfThen( aStr = 'OK', True, False ); The problem is, this form If (condition) Then Result := True; does not set Result if condition is false. So it can be undefined or random.
  8. Better. Now, refactor this so the implementation of Arguments is not visible anywhere other than inside of a constructor somewhere. Again, the whole idea of encapsulation is to hide the implementation of data so it can change without affecting how it's used by clients. IOW, if you were to change it from TArray to TList or TDictionary, none of your application code would be affected.
  9. David Schwartz

    Should my record be a class instead?

    Gotcha. My mistake.
  10. That looks a LOT better! I'd fill out the constructors. The purpose of a ctor is to initialize the state of an object. When it's a simple item like what you've got, there might be multiple ctors: one would take no arguments and return an empty object, but initialize the contents anyway just to be safe. The other(s) would offer different combinations of parameters to allow you to create and set values in one statement. Instead, you create an empty object that's not initialized, then assign values to it separately. While that's fine, it's extra coding that can be eliminated. Also, you seem addicted to using TArray, even though the way you're using it is more like a TList. You never set the initial size anywhere, which appears to be unbounded. So why not use a TList instead? In ParseFile, you don't need try...finally because you don't want to delete the object you just created b/c it's being added to a list, as your comment suggests. If you delete it, you'll end up with a list full of pointers to freed objects. Consider this instead of that whole block: AddNode( TABCStructureNode.Create( 25, 'parent_of_25', 'contents of node 25' ) ); But, if you stare at that long enough, you start to think, "why not just do this instead?" AddNode( 25, 'parent_of_25', 'contents of node 25' ); where the TABCStructureNode is created implicitly by AddNode
  11. David Schwartz

    Should my record be a class instead?

    records and classes are different. Classes already have destructors.
  12. I did not show the class definition on purpose. So that's only implied. Why don't you try writing the class definition (interface part) from what I've shown here so far?
  13. It seems you've got some heuristics in your head that are confusing you. There are no such rules. I suspect folks here could come up with a half-dozen different approaches. This is my approach. None of them is "the right approach" if they all work. I didn't put in any properties just to keep things simple for you. But you're welcome to add them and hide the explicit Get/Set methods. OOP has three legs: Encapsulation, Inheritance, polymorphism. Virtually all OOP situations involve Encapsulation; the others are only used if/when needed. All I've done is employ encapsulation. The others are not needed. In your approach, your encapsulation was overly complex and you kept trying to introduce unnecessary inheritance and composition. If you simply use a TStringlist, you don't need a class. But if you do that, all of your interactions require the client code to know exactly what your implementation is -- a TStringlist of TStringlists. Or an array of TUPLEs (or 2-member records). By encapsulating your implementation inside of a class, you can present a simple interface to the clients and completely hide the implementation. It doesn't matter if it's just one string or an entire frigging database system in the cloud with two levels of fall-back in case of failure. The client just sees one simple interface. And if you change the implementation, you don't have to change the way any other code deals with this class. That's the whole goal.
  14. Whoa. Spaghetti AND meatballs. 😮 Do NOT mix UI elements with data classes! I don't have time to unravel this mess for you. I'd start with your basic "item", which seems to be something like a TStringlist plus a name (that record thing). This could be a TUPLE of some sort. Alternatively, you could use the first entry of the stringlist to contain its own name, simply to avoid the additional structure just to have a separate identifier for it. But it may not even be necessary ... hang on. Your second level is you have a collection of these items. You use a TArray, but it could be a TList or even a TCollection. Whatever. It needs Add, Insert, Get, and Delete methods, and maybe a lookup of some kind (so you can find an "Item by name"). However, because of the simplicity of this, you could use one main TStringlist where the Strings[n] element is a 'name' and Objects[n] is a TStringlist. Then sl.IndexOf(some_name) -> n, and sl.Objects[n] -> the TStringlist (from your record). Viola! No need for a record or even an array. Just one TStringlist. Why use multiple structures when one will work fine for all needs? Technically speaking, while you could get by with just a single TStringlist, I'd wrap it into a class just to provide a simpler and more appropriate interface for it (eg., so you don't know how it's actually implemented). Memo.Lines is of type TStrings, so you'd want methods like these to interface nicely with TMemos: function TmyClass.GetItem( const nm : string ) : TStrings; var n : integer; begin Result := NIL; n := sl.IndexOf(nm); // assums 'sl' is the name of the main TStringlist in this object if (n >= 0) then Result := TStrings( sl.Objects[n] ) end; procedure TmyClass.SetItem( const nm : string; Value : TStrings ); var n : integer; sl2 : TStringlist; begin sl2 := GetItem(nm); if Assigned(sl2) then sl2.Assign(Value) else begin sl2 := TStringlist.Create(); sl2.Assign(Value); sl.AddObject( nm, sl2 ); end; end; Then when you need to get an item's value to a Memo, you'd use: memo1.Lines.Assign( myClassObj.GetItem( some_name ) ); // maybe do GetItem first to check for NIL before calling Assign in case Assign chokes if you give it NIL and to save the memo into an item buffer, you'd use: myClassObj.SetItem( some_name, memo1.Lines ); See how you're completely hiding the implementation, while providing an interface that makes using it very simple? And it knows nothing about UI elements, and yet works very simply with them. The class TmyClass is actually very simple, as it just contains a TStringlist (named 'sl' above). (Not DERIVED from it, but CONTAINS it.) The constructor would create it, and the destructor would destroy it. You'd have GetItem, SetItem, and maybe one or two other methods. That's it.
  15. I must have missed the memo on this, so I'm wondering how to deal with it. I have some local DB tables that I access with my app and all works fine. Then I decided to move the tables to a DB server. Oops. Performance issues arise. I'm using SQL components that double as Tables, so I've got to put in a SQL statement like 'select * from xyz' to get the data to load. That's fine except a couple of tables have BLOB fields that slow things down significantly when they're moved to the server. So I split the BLOB fields out into a separate table and I load them up as-needed (whenever the main table's record changes). This works fine, but it seems a bit convoluted. What I'm wondering is ... when you've got controls like listviews that only show a dozen or so lines, how do you paginate the result sets so it only loads up the records being viewed? Also, how do you NOT load up things like BLOBs unless you actually want to see them? (Since I pre-defined the tables with the fields so I can refer to field vars in the code rather than using FieldByName for everything, if I don't do a 'select * from...' then an error arises saying a data field is missing.) It would seem that the controls would need to work in conjunction with the queries to manage paging properly. There's a DBListBox in the standard palette, but no DBListView. In this case, I'm using DevExpress cxGrids, and I suspect they have a way to do this but I didn't really look into it. Do LiveBindings help solve this problem vs. regular data-aware controls? (I haven't really played with them yet.) Otherwise, how do you set up a basic pagination scheme for fetching small chunks of data from the server based on what's being viewed?
  16. David Schwartz

    General DB access question -- paging query results

    We're using Oracle 10g.
  17. David Schwartz

    Should my record be a class instead?

    When you pass everything as a string, as this guy seemed to be doing, you probably do. Or you need lots of exception handling code to deal with conversion errors.
  18. I've got a 3rd-party library and found a bug in it. The vendor fixed the bug and sent me two files they updated. It's not very practical to rebuild these libs, so I want to just load the files into the project folder and use them directly until they issue them in a formal library update. Nothing I've tried is working. I know there's a way, but I guess I'm forgetting something. What's the correct way to do this? Note that these are both for visual components. (One is for DB use, one is not, and I use them both.) There's a version property in the components that shows the version, and the newer files have a newer version#, and it's not what's being displayed.
  19. David Schwartz

    Version Control System

    I suggest git with GitHub or GitLab. I use Tower.
  20. David Schwartz

    Delphi and WebBroker on CentOS

    Given that all you need to make Delphi work on Centos is changing 9 search paths ... that's very encouraging! Can the SDK be modified to do that for each Linux project you create after that? Or will the updates be needed every time you set up a new project in that platform?
  21. David Schwartz

    Should my record be a class instead?

    In another post you showed something that's got some kind of TProject thing. You said it's a rather large structure. From what you showed, I'm guessing that you're also not allocating your records from the heap using new() because that would require you to call free() or whatever it's called. (I rarely use records, sorry.) So you've got arrays of huge records sitting in the global namespace and you're wondering why various debugging tool sare having trouble working. Have you considered that they're optimized to work with smaller chunks of things allocated from the heap at run-time? What percentage of your records are allocated from the heap? And where are all of these structures being loaded up? From a database? An INI file? Or just stuff collected at run-time? Where does it go when the program shuts down? To me, OOP is simply a way of organizing things at the source code level to make everything easier to manage. What you end up with (should be) very clear and organized. (I've seen designs that are far from it, but that's the general goal.) There are some constructs in source code that have zero impact on memory and/or execution time, so source code often appears somewhat bloated compared to non-OOP code, although a lot of it has no impact on anything. (Properties that refer to fields directly rather than via setter/getter methods, for example.) What most people focus on are the handful of things that are invisible at the source code level that DO have an impact on memory and/or execution time. This is penny-wise and pound-foolish most of the time. In your case, you just don't seem to see the value of having a tackle box to keep your tackle in rather than a toolbox, and prefer to put into whatever random bags and boxes you have around. And you put your snacks and first aid stuff into the same random bags and boxes. You're confused because a "tackle box" would seem to be derived from a "box". So what? So you seem to prefer a less organized solution instead. Or maybe a toolbox with woodworking tools, or another one with auto mechanic tools. Or maybe a matchbox with matches in it. You are pretending that these are all the same types of containers, that their contents have no particularly differentiating factors, and it's fine to put them into whatever bag or box or bottle is handy. Just don't put matches or tools into something that may get wet. Do you put gasoline into a container that isn't designed to hold liquids? Or flammable liquids? Wait, those are properties that belong to containers. But you're just using random bags, boxes, and bottles. Without having differentiating properties, any of them will do for any purpose. That's what you're saying. You could use a zip-lock baggie for your tackle and put your soda into a matchbox. What you don't realize is THAT approach means MORE CODE is needed to sift through all of the conflicting properties that should be IMPLICIT in the CONTAINERS they're in. Do you really enjoy writing all of that code? Do you realize how much of it is needed? I imagine not. A tackle box is a box; a matchbox is a box; a toolbox is a box. And you refuse to use any of them because you think the fact that they're all "boxes" and share a few common properties is ... confusing? Would you put a liquid in a box? Well, if it has a property like "can_hold_liquid" that's set to true. I have only one question for you: if you don't want to organize things in such an intuitive way, how are you managing all of this now? I guarantee you it is NOT invisible! It's just part of the mess that your code has to deal with. You don't put fishing tackle in a matchbox. But if they're each just a "box" then you need code added to each one that is intended to insure that what you put there is acceptable. Polymorphism is only confusing when you THINK you only have one kind of box in this case. Since everything is just a "box", you've probably got lines and lines of Assert statements or nested if...then...else clauses checking to see if stuff is safe to add and update. The reason is that by using properly designed classes, the COMPILER tells you when you try adding the wrong objects to things. You know the old saying: "when your only tool is a hammer, everything looks like a nail"? When you aren't using classes, your only tool might as well be a hammer, because every piece of code you write needs to check to see if the thing really IS a nail or not. Simple question for you: how much of your source code is doing nothing but checking to be sure the parameters being passed are of the correct type and/or within a legal range? If you switch to an OOP design, 99% of that code will disappear because the compiler will catch it. And I promise you that all of that extra code and complexity is increasing your maintenance overhead and technical debt considerably.
  22. David Schwartz

    Should my record be a class instead?

    @Rudy Velthuis While I agree in principle, this really has nothing to do with initializing and tearing down objects. You're still going to need to write code to DO the initialization and destruction, and then put it inside of specific methods (constructors and destructors, presumably) in order for the automated setup and tear-down logic to work, right? Whatever style of programming you use, some run-time variables WILL always need to be initialized at run-time. Whether you put them into a constructor that's called automatically or in some random function that you call to initialize global variables is irrelevant. Just don't say you dislike having to call a method to initialize your variables in one case, because it's required in ALL cases. Some just aren't as convenient. By convention, constructors in Delphi are named Create. In fact, you can name them whatever you want, even "PrepareGlobalRec" or whatever. Just change "procedure PrepareGlobalRec" to "constructor PrepareGlobalRec" and you've got a class constructor! And in many cases, you don't even need to call it. He has not saved a single line of code by avoiding using a class, but in some cases he has by using classes. The initialization code is required no matter what. But without any constructor at all, there's nothing for the memory manager to call to automatically create anything.
  23. David Schwartz

    Is it really good practice to create Forms only as needed? Always?

    Well ... I'd think more like 5 minutes per tab to copy the components into a new form. Then you need to figure out how you're going to get the data in and out, which should be the same for all of your forms (just for consistency sake). So the first four might take an hour. But after they, they'll go steadily quicker, maybe 10 minutes each. Watch my CodeRage 9 video for more insights: https://www.youtube.com/watch?v=qqKx8fQTTfI
  24. David Schwartz

    Should my record be a class instead?

    When you eat something, you need to prepare it (maybe cook it, or order it, or unwrap it), then you need to clean up afterwards. When you get in your car to go somewhere, you need to start it up; when you arrive at your destination, you need to shut it off. When you walk into a room, you may need to open the door and perhaps turn on a light; when you leave, you may need to shut the light off and close the door. Most things in life require some kind of setup, then you do something, then you clean up after yourself. Tell me it really bothers you having to deal with this constantly in your life ... or if you're like most people, you don't ever give any of it a second thought. Objects work the same way. The fallacy in your logic (and people who claim to dislike creating and freeing things) is that just because there's nothing named "constructor" or "destructor" that you're not initializing things first and cleaning up afterwards. Variables often need to be initialized and cleaned-up, regardless of their scope. By default, the compiler clears out globals automatically for you by setting them to zero, but it's risky to depend on default behaviours like that from your environment. Constructors are simply methods used for INITIALIZING an object's state. They're usually just a bunch of assignment statements. They may also create other objects required inside of the object. Simple objects that don't inherit from a parent class with a constructor that needs to be called don't need constructors. Destructors are for cleaning up when you're finished using the object. For simple classes, they're often not necessary. But if you allocate anything from the heap within the class, then they're required if you want to avoid memory leaks. However, it's a good practice to always have constructors and destructors defined, even if they're empty. And if they ARE empty, the compiler optimizes them out. The nice thing about them is they're called automatically, unlike your existing code that needs to be called explicitly. So don't tell me you dislike creating things! Classes with constructors and destructors require less code than what you're doing now ... guaranteed. Even if you're working with a bunch global variables, any nontrivial application has code that initializes groups of related variables, and breaks them down when you're finished. One of the biggest hurdles functional programmers need to overcome when learning OOP is that all of those global variables need to be collected into closely-related groups, and those groups are called "classes". Then you move the code that's already there that's used to initialize those variables into the class' constructor, and any code that's already there for cleaning up into the class' destructor. Then you want to hide the variables themselves ("encapsulation") by defining properties so if the underlying implementations change, you don't have to change every single place they're referenced. Trust me ... after you've been using OOP principles correctly for a while, it becomes second-nature, and you'll wonder how you managed to keep your sanity dealing with everything splattered all over the place with no organization whatsoever.
  25. David Schwartz

    How to create common CreateForm method?

    I did a CodeRage 9 talk on a topic that might help: https://www.youtube.com/watch?v=qqKx8fQTTfI
×