Comment by jxbdbd

16 days ago

Why would a pascal string be any shorter than a C string?

A C string is one pointer reaching all of memory, a Pascal string is two pointers reaching all of memory

A pascal string is a single byte with the length, followed by the data.

Some implementations use more bytes for the length data, such as Delphi which changed over to a 4 byte prefix length, though those aren't technically Pascal strings anymore. I can't find anything about a Pascal string being two pointers?

  • It is conceivable, for both Pascal and C, to have more than one string implementation side by side, so the developer can choose to use the best-fitting one.

    In C++23, variant<> permits to do what Rust's typed enums introduced (e.g. Result sum type that is either a "real" result - with result type - or an error - with error type -, each strongly typed).

    If you do that, a definition like

      class IString { /* basic string functions */ };
    
      class MiniString : public IString {};
      class CZeroTerminatedString : public IString {};
      class PascalString : public IString {};
      class CppString : public IString {};
    
      use String = std::variant<MiniString, CZeroTerminatedString, PascalString, CppString>; // define one type for all impl.
    

    permits to define string functions that operate over the sum type String, and which use the methods defined in the interface IString, and which then work for all string implementations.

    The developer can then pick the most suitable implementation, i.e. CMiniString for very, very short strings (that fit into 64 bits, so approx. <= 8 UTF-8 characters), CZeroTerminatedString (for char *co = "test\n"; zero-terminated old style C strings), CPascalStrings for strings that carry a length in s[0] or as a struct member or class field, and CppString as a wrapper for the C++ std::string that implements IString.

    Sum types are a type-safe and memory-preserving way to do what in the older days was sometimes implemented using a "union {}" (which was not type-safe).

  • Free Pascal strings (and i assume Delphi as they are sometimes compatible) are pointers to the first character of a null terminated string with a header in a negative offset before the first character indicating the string's length, reference count and codebase.

    AFAIK a "Pascal string" is basically another way to say "length-prefixed string" (as opposed to null terminated string) and Free Pascal (and Delphi) are like that (and they're Pascal dialects too, so their strings are literally Pascal strings :-P).

A Pascal string has a leading length byte. Because that is one byte, the text can't exceed 255 characters.

  • For modern hardware, a 64-bit length is more practical though - no alignment issues. It seems to me that Pascal's specifying a single byte prefix was a language design "mistake" of the same type as NULL termination, putting hardware considerations into the language definition. Very practical for machines of the time, but not necessarily the best choice in hindsight.

    • The original Pascal didn't had a string type, that was introduced by various dialects.

      FWIW all Pascal dialects since the 90s have a string type that allows more than 255 bytes. In Free Pascal strings are pointers to the first character with a header in a negative offset indicating the length, reference count and codepage (these fields are aligned depending on the CPU). For C compatibility the string is also null terminated so you can pass such a string to a C function and it'll work as expected. AFAIK Delphi also does the same.

    • > single byte prefix was a language design "mistake"

      Easy to say in hindsight.

      It was an optimisation made back when every single byte mattered because you might have some kilobytes of memory and a 6502 CPU (where you strongly avoided using 16 bit pointers or arithmetic - because your program would be too bloated otherwise).

      At the time Pascal was used, a whole byte for each string was seen as a waste - so fixed length strings were often used instead.

C strings (sentinel terminated strings) are infinite. Anything less than infinite is shorter than that. Anything with a known length is shorter than that. This makes them generic. Same type of constraint as you see in many algorithms.