1. Daniel Vivier
  2. PowerBuilder
  3. Sunday, 28 March 2021 01:53 PM UTC

Some years ago I saw the value in having an object that implements dictionary / associative array / map type functionality, mapping string names to arbitrary values, including strings, numbers, dates, and objects.

That could be use for passing sets of values into windows via OpenWithParm(), without having to create a different structure for each different set of values, or using some more generic structure that doesn't have named values. Sometimes I also used it for passing sets of values directly into functions, without having to have very long lists of arguments.

I came up with an implementation using a DataStore with a String key and Long index, where the index indexed into an array of Any, that held the actual values. There would have been no way to hold arbitrary values directly in a DataStore column. And I needed the index column so that I could sort the DW on the names, and the indexes into the Any array would still be correct.

Although I don't entire recall my line of thinking, When I wrote this years ago, I must have been worried that a DW Find() call to find the keys in the DataStore could be too slow, since I assumed it was basically a linear search. (One reason that was dumb is that I was almost always using a very small number of keys in the object.)

So to work around that worry, I wrote my own binary search on the keys in the DS, with a fallback linear search (using GetItem calls) in case somehow I had gotten to that lookup function without sorting the DS (which I didn't do after every add, for efficiency, but only at certain points).

The other day, it occurred to me to find out whether using Find() instead was really that much slower. I wrote some code for that, that inserted a large number of keys and values (1200), then did millisecond time of looking up each of the values in turn in the index. The binary search method took 27 milliseconds, while the Find() took 38. Obviously acceptable!

In addition I thought I should check that they were actually getting the same results, which I did by adding up the indexes returned in all of those lookups, using the two methods. Oh oh - the results were different! So I re-routed the code to use my hand-coded linear search using GetItem, and it got the same total as the Find() method. That made me suspect errors in the binary search.

Some debugging into the binary search code found that some key values that were in the DS were not being found! And then some re-reading of the DW Sort() method's Help reminded me that String sorts on DW columns are not in ASCII order, but rather "lexical order". That means that the comparisons that Sort() uses are NOT the same as the results from PB's String comparisons, < and >, which I was using in the binary search code! Bad bug, present for years, but I think we had been fortunate to not use key values in which the bug would show up!

My next thought was about the Chilkat bundle we use for a lot of other functions. It's a fabulous bundle of almost 100 well-designed and powerful ActiveX controls that we first adopted years ago for its strong SMTP support, then found more and more uses for. It's only 10MB, and very affordable, with royalty-free distribution. (No, I'm not an employee or paid to say this, just an extremely happy customer!) A list of the controls, with links to the docs for each, is at https://www.chilkatsoft.com/refdoc/activex.asp

One of the controls I had never used in that bundle was a HashTable, which of course is a traditional implementation for dictionary-type objects in programming languages. It occurred to me to use it to replace the DataStore, since it would be doing something more like a clean binary search rather than the linear search that the DS Find() does have to do. Do I coded that, and guess what - 15 milliseconds for the same 1200-item test, almost twice as fast as my broken binary search and more than twice as fast as Find().

Admittedly I don't believe we ever have that many values in this object, and speed really wasn't a concern. But still it was a fascinating adventure through this code, and a reminder of the saying "When all you have is a hammer, everything looks like a nail." In other words, a DataStore / DataWindow is not always the best solution for every single problem in PB!


Responses (1)
  1. Likes
  2. Latest
  3. Oldest
Loading...

Find Questions by Tag

.EXE .NET 6.0 .NET Assembly .NET Core 3.1 .NET Core Framework .NET DataStore .NET Std Framework 32-bit 64-bit ADO.NET AEM AI Algorithm Amazon AWS Android Apache API APK App Store App Store (Apple) Appeon Workspace Appeon Xcelerator Plug-in Architecture Array ASE Asynchronous Methods Authentication AutoBuild AutoCompiler Automated Testing Automation AutoScript Azure Barcode Base64 Batch BigData BLOB Branch & Merge Browser Bug Build Button C# C# Class Importer C# Editor C# Model generator Calendar Camera Certificate Chrome Citrix Class Client Client/Server Cloud Cluster Collection COM Command Line Compiler Compression Computed Field Configuration Controls Cookies Cordova Crash Cross-Platform Crosstab CSharpAssembly CSharpObject CSS CSV Cursor Data Database Database Driver Database Painter Database Profile Database Provider DataObject DataSource DataStore DataStore (C#) DataStore (PS) DataType DataWindow DATE DATETIME DB2 Debug Debugger Debugging Deployment Design DLL DO-WHILE Dockable Docker Documentation DOUBLE Download DragDrop Edge Edit Style Editor Elevate Conference Email Embedded SQL Emulator Encoding Encryption Enhancement Request Entity Entity Framework ERP Error Event Event Handler Event Handling Excel Exception Export Expression External Functions F# Field File File Access Filter Firefox Firewall Font FOR-NEXT Foreground Format Function Garbage Collection GeoLocation Git Graph HANA Hash Header HTML/5 HTTP/S HTTPClient Icon IDE Identity IIS IMAPI Import InfoMaker Inheritance Installation Integer IntelliSense Interface Internet Internet Explorer iOS IPA iPad iPhone IWA J# Java JavaScript JBoss JDBC JOIN JSON JSONGenerator JSONParser Kestrel Label Lambda Large File LDAP Library License LINQ Linux OS Load Balancing Localization Localized PBVM Log In Log Out Logging LONG LONGLONG macOS MAPI Maps MDI Memory Memory Leak Menu Merge MessageBox Messagging Method Migration MIME TYPE Mobile Model ModelStore ModelStore (C#) MSOLEDBSQL Multi Threading MVC MySQL n-Tier Namespace NativePDF NVO OAuth ODATA ODBC Office Offline OLE OLEDB Online Open Source OpenAPI OpenSSL Oracle OrcaScript Other Outlook Output Package Parameter Patch PayPal PB Classic PB Native PB.NET PBC PBD PBDOM PBG PBJVM PBL PBNI PBORCA PBVM PBX PDF Performance Permission PFC Picture Pipeline Play Store (Google) Plugin Popup Port POST PostgreSQL PowerBuilder PowerBuilder (Appeon) PowerBuilder (SAP) PowerBuilder Compiler PowerBuilder Runtime PowerClient PowerScript (PS) PowerScript IDE PowerScript Migrator PowerServer PowerServer Mobile PowerServer Toolkit PowerServer Web PowerServerLabel Print Properties Proxy Publish PULL PUSH Query Regression Release Renew Resize Response REST Retrieve RibbonBar RibbonBar Builder Rich Text Roadmap RPC Runtime Packager SaaS Scaffolding Script SDI SDK Security Server Service Session Single Sign-on Size SMTP SMTPClient SnapDevelop SOAP Sort Source Code Speech Recognition SQL SQL Anywhere SQL Server SqlBuilder SqlExecutor SQLite SqlModelMapper Storage Stored Procedure Subscription SVN Swagger Syntax TabbedBar TabbedView Tablet TabPage Target TE Control Testing Text TFS Theme TIME Timer TLS/SSL Tomcat TortoiseGit TortoiseSVN Transaction Transparency Trial Trigger TRY-CATCH TX Control Type UI ULONG UltraLite Uninstall Unit Test Unit Testing UNIX OS Update Upgrade Upload URL User Center User Object UWP Validation VARCHAR Variable Versioning Visual Studio Visual Studio Code VM Voice Warning WCF Web API Web Extensions Web Service WebBrowser WebForms WebLogic WebSphere WildFly WinAPI Window Windows OS WinForms Wizard Workgroup Workspace WPF XCODE XHTML XML Zoom

Helpful?

If a reply or comment is helpful for you, please don’t hesitate to click the Helpful button. This action is further confirmation of their invaluable contribution to the Appeon Community.