Behind the connection: Internet Explorer Automation Part 3
DelphiTools.info: Immutable strings… in Delphi?
One of the “novelties” of the NextGen Delphi compiler is immutable strings, which I find quite puzzling, for lack of a better word, given that Delphi already had reference-counted copy-on-write strings, and the NextGen compiler uses reference-counted strings.
I always considered that Delphi’s String type was one of its remaining strong points, being a high-level abstraction (higher than Java’s or .Net’s String/StringBuilder dichotomy) with excellent low-level performance (on par with C/C++ character arrays).
From the recent discussions, it appears many don’t know what makes/made Delphi String so special, so here is a quick summary.
Immutability
String being immutable means you can keep a single reference across threads without trouble. That’s an advantage over C strings.
It also means that copying a string, be it for an assignment or a parameter passing, is just like passing a reference, you don’t have to duplicate the content if you want to be sure it isn’t modified behind your back. That’s an advantage over C strings and StringBuilder.
Note that none of the above are advantages over Delphi Strings, since the copy-on-write mechanism means that Delphi Strings are effectively immutable once they’re referenced more than once.
Reference-counting vs Garbage Collection
Every time a new assignment or parameter passing is made, the reference count of the String has to be increased, this is an atomic lock, and is related to memory management, so it’s there whether you’re using simple reference-counting or copy-on-write.
Under a GC, no atomic lock is required, a simple reference (pointer) has to be copied. This is very efficient, locally, but the memory management costs are just deferred to a later garbage collection phase. Since immutable strings don’t have reference to other objects, the GC for them can theoretically happen in parallel without any drawbacks (assuming the GC supports it).
So under a GC, an immutable String type makes a whole lot of sense, as implementing a copy-on-write one requires a lot of effort, and a mutable one is problematic multi-threading wise.
Copy-on-write mutability
Making reference-counted strings mutable doesn’t change any of the above, you just add one capability: when the reference count indicates there is no other reference to a string, then you can mutate it, ie. change characters, adjust its length, etc.
In other words, when the only reference to a string is a single variable locally scoped to a procedure, then it’s safe to do just about anything with it, the multi-threading issues can’t apply until that string is referenced somewhere else.
This is both convenient and very efficient, since what the compiler does before applying a mutation can be summarized as:
if myString is "referenced somewhere else" then
myString := make a local copy of my String
mutate myString
The local copy is of course referenced nowhere else, and thus is safe to mutate. Copy-on-write is really copy-on-mutate, as it encompasses just not changing the characters, but also resizing a string (re-allocations) and concatenations.
Keep in mind this is an “added-on” behavior, where you just take advantage of the memory management scheme being a reference-counting one. If you know what you’re doing and want more performance, you can even waive the COW check by using UniqueString(), which will ensure you have a local copy, and then acquiring a PChar to the string content.
It can be done under a GC, but means you have to maintain a reference count or similar information since the GC doesn’t have one. Android relies a lot on copy-on-write, and that was actually one key differentiation between Dalvik VM and more classic Java VM.
Advantages of RawByteString & UTF8String over TBytes
And this will be a bit more controversial, but Copy-On-Write is also why RawByteString/UTF8String can ofttimes make a lot more sense than TBytes for binary buffers: RawByteString isn’t just reference-counted (like TBytes), it is also supporting copy-on-write.
This means that in a multi-threaded environment, RawByteString shares the same advantages of immutability String enjoys, and which TBytes just doesn’t enjoy, as TBytes is always mutable.
Conclusion
String wraps up both advantages of Java/.Net String & StringBuilder, they have bother multi-threading immutability advantages and the mutability capability.
Performance-wise, under a speculative memory manager (like most modern allocators), you’ll also find that merely concatenating to a String is typically just as fast as using TStringBuilder, and in several occurrences it’s actually faster because String benefits from compiler magic, while TStringBuilder does not (also some TStringBuilder implementations are a little weak).
Alas some String performance was lost during the Unicode and 64bit transition, when some FastCode routines where replaced by lower performing pure-pascal ones, and you’ll lose even more performance with TStringHelper, which introduces some algorithmically poor pure-Pascal implementations.
Smart Mobile StudioSmart Mobile Studio: Smart Mobile Studio 1.1 RC (build 1.1.0.400)
The Wiert Corner - irregular stream of stuff: jpluimers
I had some notes on Delphi WSDL and SOAP peculiarities somewhere, but I misplaced them.
Luckily, I found some links that explain most of my notes well:
- Passing nil values for simple types
As of Delphi 2007 you can do this by using TXS… types as mjn summarized in delphi – Blank value in web service for Int64 type – Stack Overflow.
(I wish a few people would vote to re-open the question. It is not too localized as it applies to everyone wanting to pass 64-bit integer types over SOAP to/from Delphi). - Document/Literal versus RCP encoded SOAP
Delphi defaults to RPC Encoded, which is not WS-I Compliant, but Document/Literal style is.
The Delphi SOAP framework is not listed to be compliant to the WS-I Basic Profile, but it works fine in Document/Literal style mode.
Aaronaught explains this in c# – Delphi SOAP Envelope and WCF – Stack Overflow.
–jeroen
Filed under: Delphi, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Development, SOAP/WebServices, Software Development
while true do;: My Delphi STOMP Client is now compatibile with iOS
Firebird News: Firebird Python driver FDB 1.1.1 is released
Behind the connection: Be-Delphi Event 3.0
The Wiert Corner - irregular stream of stuff: jpluimers
It is unwise to pass objects allocated in one framework over a DLL boundary to a different framework.
In the case of Using C dll in delphi return nothing, someone tries to pass an Interface to some memory in the C side over to Delphi.
Unless that interface is COM based, don’t do that!
In a more general way: don’t pass memory allocated on the DLL side over to the client side, no matter what kind of client you have.
From the DLL, either pass simple types, or fill buffers allocated at the client side.
–jeroen
via: Using C dll in delphi return nothing – Stack Overflow.
Filed under: Delphi, Delphi 1, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Development, Software Development
while true do;: Book Review: ZeroMQ (PACKT Publishing)
Delphi Code Monkey: A very frustrating issue with Microsoft SQL Express
- Shared Memory
- Named Pipes
- TCP/IP
- On some client computers, using an SQL connection string that does not specify named pipes explicitly, Named pipes will be chosen first, and everything will work.
- On some client computers on the same local area network and domain, the same SQL connection string that does not explicitly specify named pipes, TCP/IP will be chosen first, and will fail.
- Hack the connection string so it forces named pipes. This must be made configurable in your Delphi application though or you'll be stuck where I was stuck at the beginning of this blog post, with some of your clients (who are unable to use Named Pipes) also unable to use your application. If this is a "set it and forget it hack" done in the background with no UI to select this hack on or off, this will solve one problem while creating another one, so you're just sweeping the issue "under a carpet" and making it harder for someone else in the future.
- Make your connection string configurable. This is flexible, but it makes configuring your application harder.
- Disable the misconfigured TCP/IP option completely on the server, this will make the negotiation (use named pipes? use tcp/ip? Let's check what's available and try one) go faster, but for many users Named Pipes are significantly SLOWER than working with TCP/IP.
- Fix the TCP/IP configuration on the server, using SQL Server Configuration Manager. Make sure that your SQL Server static port is set to 1433, and that your dynamic port option is set to blank (not configured).
DelphiTools.info: LLVM for DWScript
Very experimental support for LLVM in DWScript is now in the googlecode repository, thanks to the efforts of Christian-W Budde.
This is the beginning of the opening of new realms of possibilities for DWS!
LLVM support is currently centered around jit compilation, and at the moment doesn’t extend much beyond the needs of the Mandelbrot demo (see below for what is supported right now).
LLVM CodeGen vs dwsJIT
Note that it is a different effort from the recently announced JITter for DWS, the TdwsJIT is a simple greedy just in time compiler, which works on the same structures as the interpreter, and where a goal is that jitting should be lightweight and fast enough to be applied all the time. It’s a “cheap” boost to script execution, and a hybrid architecture (cf. future article).
The LLVM codegen on the other hand involves a bit more overhead, in terms of a large DLL and longer compilation/JITting times, but has a wealth of other benefits.
The LLVM codegen isn’t tied to the interpreted structures, so it means more work down the road to get everything working, but there is much greater optimization potential, and the natively compiled code can be cached or persisted (thus mitigating or negating the compilation overhead).
Finally LLVM is of course cross-platform, and there is the potential for compiling standalone binaries as well…
Performance
No exact performance figures just yet, it’s too early and they change too often!
From initial tests, LLVM with optimization level zero (no optimization) is in the same ballpark as the dwsJIT, though with a slight JIT overhead (dwsJIT has none).
When increasing the optimization level, LLVM takes a measurable amount of time, but produces the best compiled binary on the benchmark so far! It’s only behind the hand-optimized version, and not all optimizations in LLVM are active just yet…
What’s working
Note that this is a very temporary list, as things change rapidly, so use it more as “cheat list” for what you can test right now.
What is working so far:
- Primitive expressions
- Integer
- Arithmetrical (Add, Sub, Mul, Div, Mod, Neg, Sqr & Abs)
- Arithmetrical assigns (+=, *=, -=, …, see above)
- Bit Manipulations (Sar, Shr, Shl, And, Or, Xor, Not)
- Comparisons (Less, LessEqual, Equal, GreaterEqual, Greater)
- Shortcuts such as Inc & Dec
- Min & Max (inlined)
- Float
- Arithmetrical (Add, Sub, Mul, Div, Neg, Sqr, Abs, Sqrt, Sin, Cos, Power, Exp, Ln, Log10, Log2)
- Arithmetrical assigns (+=, *=, -=, …, see above)
- Conversions (Floor, Ceil, Trunc, Round)
- Comparisons (Less, LessEqual, Equal, GreaterEqual, Greater)
- Min & Max (inlined)
- Boolean
- Logical (And, Or, Xor, Not)
- Integer
- Aggregate Types
- Arrays
- simple array types (read only!)
- only primitive types
- Records
- simple record types
- nesting is not thoroughly tested yet
- may not contain arrays
- Strings
- only constant strings
- Arrays
- Control Flow Expressions
- Branches
- If / Then
- If / Then / Else
- If / Then / Else -> Value
- Loops
- while
- repeat
- for (upward / downward, fixed / variable steps)
- Functions
- using simple variables (no var or const yet)
- main function (typically without declaration in DWS)
- may be called from other functions
- PrintLn (to print constant strings, rely on external definition)
- Branches
And here’s the list of things that are not working:
- Strings and string management (except for string constants)
- obviously no helpers as well
- Resource strings
- Dynamic arrays
- Variants
- complex array types (containing non-primitive values)
- complex record types (containing non-primitive values)
- Classes
- Fields
- Methods
- Constructors
- Self
- Visibility
- Interfaces
- Objects
- Case
- Special loop aware
- ForCharIn / ForCharCodeIn
- Continue / Break / Exit / Exit(Value)
- Exceptions (try, finally, except, raise, assert)
- Helpers
- Connectors
- Special math functions like Tan, Arc*, etc.
TPersistent: Time to Jump into the Delphi Pond?
If you’re a new developer and you’re wondering what development tool to adopt you have to decide what pond you want to play in. Don’t be suckered by the vendor offering free conferences, and trial development tools. Don’t “go with the flow” and choose the most popular tool because no one ever got fired for choosing it. If you do, it doesn’t say much for your critical thinking capabilities. You will be competeing with every Tom, Dick and Harry out there who is doing the exact same thing. There may be plenty of jobs, but the pay rates are driven down by the market. If you have mobility and travelling around the world appeals to you, then consider a small technology pond. One like Delphi, that is a pleasure to work with, and has a devoted following. Employers are finding it more difficult to acquire qualified staff, and are willing to offer more to good candidates and do more to retain them. You can work throughout the world for good rates, when going with a more mainstream technology, employers will choose local resources. It’s also becoming more common place to telecommute, if that is your goal.
Now don’t get me wrong, I am not saying bet your livelihood on a niche technology. I am saying position yourself with technologies (note the pluralization) so you can maximize the revenue generated from their use. That generally happens on the bleeding edge, and the twilight years. Talk to any Cobol developer about the kind of money you can make on a technology in it’s twilight years. Talk to any SAP consultant about the kind of money they make in a niche technology, and then ask your average .NET developer about the rates they get. Talk to any Objective C developer who made a fortune on the iPhone boom. Get the picture?
As a developer you should know at least two languages you can make a living with. This mitigates the risk of one of them being a niche technology, and protects you from shorter term market fluctuations. The exposure to different techniques also makes you a better developer. Today, choosing a mobile platform is likely as important as choosing a web platform was 10 years ago. As technologies converge, it’s important to have exposure to both web and desktop. Picking a platform that supports both reduces the number of languages and technologies you have to be fluent with.
Delphi offers a long history of backwards compatibility, and significant popularity (read lots of code to maintain). It’s community members are often as zealous as Apple fans and are very helpful to newies. Delphi offers many of the same features as newer languages, and has support for web, mobile and desktop to varying degrees. If FireMonkey and Embarcadero’s mobile efforts succeed, developers could experience “bleeding edge” type results in what would otherwise be a product’s twilight years.
As a niche product, or if you are an aspiring ISV, I think Delphi is worth serious consideration.
Firebird News: 10th FDD – Subscriptions are open!
Behind the connection: Pascal still an advantage for some iOS, Android developers
The Wiert Corner - irregular stream of stuff: jpluimers
One of the things you must be careful with is reentrancy in your application through a message loop.
The most obvious way is Application.ProcessMessages: it will loop until all messages from the Windows message queue are processed, whether your application is ready for them or not.
A less obvious way is because of modal dialogs or forms. They have their own message loop which might cause global reentrancy in your application (for instance through TTimer objects).
That was the case for this problem: stack overflow with repeated DispatchMessageW in the call stack.
A couple of ways to try to avoid these issues:
- Don’t cause a secondary message loop.
You can refrain from calling Application.ProcessMessages, but you cannot always avoid modal dialogs. - Protect each of your event handlers by disabling the path to it as soon as it gets called.
This means disabling the Enabled property for instances of TTimer, TControl, TAction, or other objects that cause events.
–jeroen
via: windows – stack overflow with repeated DispatchMessageW in the call stack – Stack Overflow.
Filed under: Delphi, Development, Software Development
Behind the connection: Internet Explorer Automation Part 4
The Wiert Corner - irregular stream of stuff: jpluimers
On my research list (Thanks Uwe!): DataSnap in the Cloud – DelphiFeeds.com.
It shows you how to do DataSnap from the Azure clound, including getting some of the default Delphi database demos to work on SQL Server (erm, SQL Azure).
–jeroen
Filed under: Delphi, Delphi XE, Delphi XE2, Delphi XE3, Development, Software Development
Andreano Lanusse | Technology and Software Development: Android Studio preview The new Google IDE is out
Last week at Google I/O, Google announced Android Studio, their new Android development environment based on IntelliJ IDEA.
Android Studio is FREE and can download the early preview version here. I just installed on my Mac, the IDE supports Windows and Linux as well. I played a little bit during the last 2 days and I’m very impressed.
Today’s Android development is supported in Eclipse through the ADT (Android Development Toolkit plugin), and every developer can take advantage of the Eclipse ecosystem. I have been using Eclipse for Android development, but certainly I see space for improvement and more specific features related to Android development.
Android Studio is built on top of IntelliJ’s community version and now with Google Engineer working on that , just imagine what they will be able to produce. I just played few hours with Android Studio, their source code editor ROCKS it goes beyond of features already applied in other IDEs, the Designer is awesome and gives you a view of your application not only for one device, but for many others include tablets. Also, you can easily import your projects from Eclipse in to Android Studio.
Watch the following video and you will have a pretty good idea about what I’m talking about.
That’s it for now.
Related Posts
Andreano Lanusse | Technology and Software Development
Follow me on Twitter: @andreanolanusse
The Wiert Corner - irregular stream of stuff: jpluimers
So I won’t forget:
delphi – How to distinguish flash drives? – Stack Overflow.
In that answer, Dan C talks about VID / PID (Vendor ID and Product ID) and how to get some of the serials without WMI.
–jeroen
Filed under: Delphi, Delphi XE3, Development, Software Development