Synopse

To content | To menu | To search

Tag - string

Entries feed

2015, Friday May 8

I do not like people shoot in my foot, do you?

There was some discussion about the new TStringHelper feature introduced in latest versions of Delphi.
I was told to be some kind of archaic guy, not able to see the benefit of this.
Reducing opinions to a conservative/progressive approach - another famous 10 kinds of coders - is very reductive.

Of course, this was IMHO unfair and my point was that I have the feeling that some decisions about the Delphi language and RTL are inadequate.
Some changes are welcome. I enjoy the introduction of generics - even if it is was painful, and even buggy (do not use TList<T> with managed record types in XE8!).
But some upcoming changes about the string policy - breaking everything just because we want to align with mainstream C# or Java habits - are just non sense to me.
I really think that Embarcadero deciders like to shoot their own foot.
Or - certainly worse - our own feet!

I will post here some part of the discussion...
So that we may be able to share our ideas.

Continue reading...

2015, Monday April 20

Delphi is not a cross-compiler, but a set of cross-compilers

It is worth saying again.
I'm not speaking this time about performance issues, but about a common misunderstanding of what the latest version of Delphi offers.

Since Delphi "NextGen" compilers did break the memory model (introducing ARC), and also reducing low-level types (e.g. RawByteString/AnsiString), we can not say that Delphi is a single cross-compiler.
In practice, it has a set of cross-compilers.

Continue reading...

2014, Wednesday May 7

Benchmarking Mustache libraries: native SynMustache vs mustache.js/SpiderMonkey

I just wrote a small sample program, for benchmarking Mustache libraries: native SynMustache vs mustache.js running on SpiderMonkey 24...

And the winner is ...SynMustache, which is 10 times faster, uses almost no memory during process, and handles inlined {{>partials}} natively (whereas we have to handle them manually with mustache.js)!

Who says that Garbage Collection and immutable strings in modern JITted runtimes are faster than "native" Delphi applications?
Are you still preferring the "NextGen" roadmap?

Continue reading...

2014, Saturday March 29

Enhanced and fixed late-binding of variants for Delphi XE2 and up

For several units of our framework, we allow late-binding of data values, using a variant and direct named access to properties:
- In SynCommons, we defined our TDocVariant custom variant type, able to store any JSON/BSON document-based content;
- In SynBigTable, we use the TSynTableVariantType custom variant type, as defined in SynCommons;
- In SynDB, we defined a TSQLDBRowVariantType, ready to access any column of a RDBMS data result set row;
- In mORMot, we allow access to TSQLTableRowVariantType column values.

It's a very convenient way of accessing result rows values. Code is still very readable, and safe at the same time.

For instance, we can write:

var V: variant;
 ...
  TDocVariant.New(V); // or slightly slower V := TDocVariant.New;
  V.name := 'John';
  V.year := 1972;
  // now V contains {"name":"john","year":1982}

This is just another implementation of KISS design in our framework.

Since Delphi XE2, some modifications were introduced to the official DispInvoke() RTL implementation:

  1. A new varUStrArg kind of parameter has been defined, which will allow to transmit UnicodeString property values;
  2. All text property values would be transmitted as BSTR / WideString / varOleStr variants to the invoked variant type;
  3. All textual property names were normalized to be in UPPERCASE.

Those modifications are worth considering...
And we may have discovered two regressions: one about speed, and the other about an unexpected logic bug...

Continue reading...

2014, Tuesday February 25

TDocVariant custom variant type

With revision 1.18 of the framework, we just introduced two new custom types of variants:

  • TDocVariant kind of variant;
  • TBSONVariant kind of variant.

The second custom type (which handles MongoDB-specific extensions - like ObjectID or other specific types like dates or binary) will be presented later, when dealing with MongoDB support in mORMot, together with the BSON kind of content. BSON / MongoDB support is implemented in the SynMongoDB.pas unit.

We will now focus on TDocVariant itself, which is a generic container of JSON-like objects or arrays.
This custom variant type is implemented in SynCommons.pas unit, so is ready to be used everywhere in your code, even without any link to the mORMot ORM kernel, or MongoDB.

TDocVariant documents

TDocVariant implements a custom variant type which can be used to store any JSON/BSON document-based content, i.e. either:

  • Name/value pairs, for object-oriented documents;
  • An array of values (including nested documents), for array-oriented documents;
  • Any combination of the two, by nesting TDocVariant instances.

Here are the main features of this custom variant type:

  • DOM approach of any object or array documents;
  • Perfect storage for dynamic value-objects content, with a schema-less approach (as you may be used to in scripting languages like Python or JavaScript);
  • Allow nested documents, with no depth limitation but the available memory;
  • Assignment can be either per-value (default, safest but slower when containing a lot of nested data), or per-reference (immediate reference-counted assignment);
  • Very fast JSON serialization / un-serialization with support of MongoDB-like extended syntax;
  • Access to properties in code, via late-binding (including almost no speed penalty due to our VCL hack as already detailed);
  • Direct access to the internal variant names and values arrays from code, by trans-typing into a TDocVariantData record;
  • Instance life-time is managed by the compiler (like any other variant type), without the need to use interfaces or explicit try..finally blocks;
  • Optimized to use as little memory and CPU resource as possible (in contrast to most other libraries, it does not allocate one class instance per node, but rely on pre-allocated arrays);
  • Opened to extension of any content storage - for instance, it will perfectly integrate with BSON serialization and custom MongoDB types (ObjectID, RegEx...), to be used in conjunction with MongoDB servers;
  • Perfectly integrated with our Dynamic array wrapper and its JSON serialization as with the record serialization;
  • Designed to work with our mORMot ORM: any TSQLRecord instance containing such variant custom types as published properties will be recognized by the ORM core, and work as expected with any database back-end (storing the content as JSON in a TEXT column);
  • Designed to work with our mORMot SOA: any interface-based service is able to consume or publish such kind of content, as variant kind of parameters;
  • Fully integrated with the Delphi IDE: any variant instance will be displayed as JSON in the IDE debugger, making it very convenient to work with.

To create instances of such variant, you can use some easy-to-remember functions:

  • _Obj() _ObjFast() global functions to create a variant object document;
  • _Arr() _ArrFast() global functions to create a variant array document;
  • _Json() _JsonFast() _JsonFmt() _JsonFastFmt() global functions to create any variant object or array document from JSON, supplied either with standard or MongoDB-extended syntax.

Continue reading...

2013, Saturday May 11

Delphi XE4 NextGen compiler: using byte instead of ansichar?

When I first read the technical white paper covering all of the language changes in XE4 for mobile development (tied to the new ARM LLVM-based Delphi compiler), I have to confess I was pretty much confused.

Two great mORMot users just asked for XE4/iOS support of mORMot.

Win32/Win64 support for XE4 will be done as soon as we got a copy of it.
I suspect the code already works, since it was working as expected with XE3, and we rely on our own set of low-level functions for most internal work.

But iOS-targetting is more complex, due to the NextGen compiler, mainly.

Continue reading...

2012, Thursday December 20

How to make it fast?

On our forum, a clever question was posted about publishing some enhanced RTL functions for newer versions of Delphi - as we did for Delphi 7 and 2007.

I was looking for a faster IntToStr implementation and discovered SynCommons.pas.
(....)
That's really too bad, SynCommons.pas really does contain some seriously fast stuff, people would greatly benefit from it if it was made general-purpose.

In fact, it would not be enough to change the RTL function implementations.
IMHO, to write something scalable, you need to get rid of such functions.

Continue reading...

2012, Saturday October 6

Delphi XE3 is preparing (weak) reference counting for class instances

In Delphi, you have several ways of handling data life time, therefore several ways of handling memory:

  • For simple value objects (e.g.  byte integer double shortstring and fixed size arrays or record containing only such types), the value is copied in fixed-size buffers;
  • For more complex value objets (e.g. string and dynamic arrays or record containing such types), there is a reference counter handled by each instance, with copy-on-write feature and compiler-generated reference counting at code scope level (with hidden try..finally blocks);
  • For most class instances (e.g. deriving from TObject), you have to Create then Free each instance, and manage its life time by hand - with explicit try..finally blocks;
  • For class deriving from TInterfacedObject, you have a RefCount property, with _AddRef _Release methods (this is the reference-counted COM model), and you can use Delphi interface to work with such instances - see this blog article.
With Delphi XE3, we were told that some automatic memory handling at class level are about to be introduced at the compiler and RTL level.
Even if this feature is not finished, and disabled, there are a lot of changes in the Delphi XE3 Run Time Library which sounds like a preparation of such a new feature.

Continue reading...

2012, Tuesday July 10

Better Unicode support in Reports and PDF generation

By default, both GDI+ anti-aliased drawing and PDF file generation using our libraries did lack of font-fallback implementation.

If some of the characters in a string are not supported in a requested font, they were drawn as square symbols on the GDI+ canvas or the PDF content.

The font-fallback mechanism implemented will use a third-party font (Arial Unicode MS by default, which is installed with Microsoft Office), for any glyph that are missing when rendering the content. Of course, for PDF generation, you are able to embed the font within the generated file (this is by the way mandatory for PDF/A-1 format).

Both of these new features are handled by the SQlite3Pages unit, i.e. for report anti-aliased drawing preview and PDF generation.

By the way, the TGDIPages class itself (the one used for report generation from code) now handles by default Unicode text, even with Delphi versions prior to 2009 (via the SynUnicode string type, which maps WideString before Delphi 2009, then UnicodeString starting with Delphi 2009). Does make sense with such a font-fallback mechanism.

Continue reading...

2012, Tuesday April 10

How function results are allocated

One potential issue with Delphi coding, is about how the result of a functions are implemented.

If you forget to set a result value to a function, you'll get a compiler warning.
Never underestimate such warning: IMHO this is not a warning, but an error.

And you should better be aware of the handling of reference-counted types (e.g. string) in a function results: those are passed the stack as var parameters, so the result of a function may be set even if an exception is raised during function execution!

Continue reading...

2012, Thursday February 9

Using SetLength or SetString

Some Delphi users even do not know the existence of the SetString function.

As stated by the official documentation:

procedure SetString(var S: String; Buffer: PChar; Length: Integer);

For a long string variable, SetString sets S to reference a newly allocated string of the given length. If the Buffer parameter is not nil, SetString then copies Len characters from Buffer into the string; otherwise, the content of the new string is left uninitialized. If there is not enough memory available to create the string, an EOutOfMemory exception is raised. Following a call to SetString, S is guaranteed to reference a unique string (a string with a reference count of one).

Some have noticed that in our libraries, I sometimes use SetString instead of SetLength.
When the string is already allocated, it could be faster to use SetString, if you are sure that you will overwrite the string content.

Continue reading...