Lazarus

Free Pascal => General => Topic started by: AlexTP on December 27, 2020, 04:02:37 pm

Title: Idea of multi-line strings, mantis 35827
Post by: AlexTP on December 27, 2020, 04:02:37 pm
https://bugs.freepascal.org/view.php?id=35827
I only want to suggest a syntax for multi-line strings:

case1)

Code: Pascal  [Select][+][-]
  1. var s = 'begin'/
  2. 'mdl'/
  3. 'end.' ;

Here we use / which is not defined for strings.

case2)

Code: Pascal  [Select][+][-]
  1. var s = "begin
  2. mdl
  3. end" ;

Here we use dbl-quotes.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: AlexTP on December 27, 2020, 04:10:15 pm
(I edited the post after 5 minutes of thinking)
Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 27, 2020, 04:18:49 pm
I like the double quotes version.

About using "/" it seems to be redundant with "+".
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 27, 2020, 04:23:56 pm
I think that + already works. However if it were my project:

* I'd add _ as a concatenation operator for strings and dynamic arrays, so that it was possible to redefine + as vector addition.

* I'd definitely not mess around with " since in scripting languages I've allowed stings defined with different types of quotes to have different properties (e.g. a string quoted by / to be a regex or backref).

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 27, 2020, 04:36:40 pm
About the vector addition, that's another (interesting) topic.

I don't see how the usage you do in scripting languages interferes here. It is not the same interpreter.

Another approach is to allow strings to be multiline.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: AlexTP on December 27, 2020, 04:41:18 pm
case3)
Like in Python with prefix char 'r', here with 'm':

Code: Pascal  [Select][+][-]
  1. var s = m'begin
  2. mdl
  3. end' ;
  4.  
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 27, 2020, 05:55:02 pm
I don't see how the usage you do in scripting languages interferes here. It is not the same interpreter.

Easily-entered characters are in short supply and shouldn't be squandered, I gave one example of how additional quote types could be beneficial.

Another would be if single-quoted strings defaulted to single-byte characters, and double-quoted strings to Unicode.

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: marcov on December 27, 2020, 09:08:19 pm
Better load them from resources, easier to post compilation translate them
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 27, 2020, 09:33:59 pm
There was an effort to introduce multiline string, I have no idea what happened with that.

I strongly disagree with that idea, for reasons I gave here: https://forum.lazarus.freepascal.org/index.php/topic,46050.msg330104.html#msg330104 (https://forum.lazarus.freepascal.org/index.php/topic,46050.msg330104.html#msg330104)
Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 27, 2020, 09:57:10 pm
Better load them from resources, easier to post compilation translate them
How would you do that actually?
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 27, 2020, 10:09:12 pm
Better load them from resources, easier to post compilation translate them
How would you do that actually?

I'm not a core developer, but I think a good case could be made for something handled at the same level as the rest of the conditional directives particularly for stuff like SQL:

const
  myQuery=
{$' terminator
Stuff here
terminator }

But I really don't like screwing the core language any further for this sort of thing.

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Warfley on December 27, 2020, 10:53:30 pm
With the double quotes there is one problem, it breaks indentation because the indent would be part of the string. And while as functions in variables this might not look so bad, look at this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TTestClass = class
  3.   public const
  4.     Description = "This
  5. is
  6. a
  7. multiline
  8. description";
  9.     SomethingElse = 42;
  10. ...
personally I think this is really ugly.

There is also the question should multiline strings contain the linebreaks or not?
If it shouldn't i.e. just be a convinient way to chop up a string to large for a sinlge line, there is nothing wrong with the + syntax:
Code: Pascal  [Select][+][-]
  1. var
  2.   mls = "multi"+
  3.         "line" +
  4.         "string";
If it should, then imho a simple newline symbol would make more sense. Most languages use escape characters like \n like in C#:
Code: C  [Select][+][-]
  1. String mls = "this is a\n" +
  2.              "multiline\n" +
  3.              "string";
In pascal we have the #num for directly appending chars:
Code: Pascal  [Select][+][-]
  1. var mls: String = "this is a"#10 +
  2.                   "multiline"#10 +
  3.                   "string";
Which works fine for most special chars (like tab #9) but of course newline is different on windows (#13#10) and unix (only #10).
I think therefore a more "pascallian" way would be to have special sequences with #, like #n for newline, which is on windows treated as #13#10 and on unix as #10.

But there is already a solution to that that works perfectly fine in current fpc:
Code: Pascal  [Select][+][-]
  1.   {$Macro on}
  2.   {$Define ln:=+ LineEnding}
  3. const
  4.   mls = 'multi'ln +
  5.         'line'ln +
  6.         'string';
If you like to also leave out the +:
Code: Pascal  [Select][+][-]
  1.   {$Macro on}
  2.   {$Define ln:=+ LineEnding +}
  3. const
  4.   mls = 'multi'ln
  5.         'line'ln
  6.         'string';
Title: Re: Idea of multi-line strings, mantis 35827
Post by: speter on December 28, 2020, 12:08:18 am
I think it would be simpler to just use:
Code: Pascal  [Select][+][-]
  1. foo := 'something'+slinebreak+
  2.        'next line'+slinebreak+
  3.        'etc';
cheers
S.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lucamar on December 28, 2020, 12:42:53 am
Better load them from resources, easier to post compilation translate them
How would you do that actually?

Lots of ways, for example:

What we actually do is to use string concatenation with C-like scapes, e.g.
Code: Pascal  [Select][+][-]
  1. const {or resourcestring}
  2.   sBanner = 'I Made It! First Ever Algorithm\n' +
  3.             'Copyright 1842 by Ada A. Lovelace';
which we then pass through an "unscape' function when in use. But I realize this is just a crutch; it would be nicer if  the compiler allowed us to, at least, use another operator meaning "add a line end before concat", if not a special "multiline string" construct. Say. something like (just an example!):
Code: Pascal  [Select][+][-]
  1. const {or resourcestring}
  2.   sBanner = 'I Made It! First Ever Algorithm' *
  3.             'Copyright 1842 by Ada A. Lovelace';
instead of:
Code: Pascal  [Select][+][-]
  1. const {or resourcestring}
  2.   sBanner = 'I Made It! First Ever Algorithm'  + LineEnding +
  3.             'Copyright 1842 by Ada A. Lovelace';

And, yeah, let's not kid ourselves: the main drive for this feature is to save typing ;) but it also helps to prevent some annoying bugs, like forgetting one (or more!) of those "  + LineEnding +" or adding one where it's not wanted when you're adding a "wall-of-text" constant like, say, a console program "help". Of course, one could (like I do sometimes) just write that wall of text in its own text file and pass it through a "pascalifier", but again: less typing? lazy programmers? don't make the tool chain too long or you'll tangle in it? :D

Ok, I'm running out of ink; I'll stop here ("wall of text", indeed!) ::)


Oh! Just one thing:

But there is already a solution to that that works perfectly fine in current fpc:
Code: Pascal  [Select][+][-]
  1.   {$Macro on}
  2.   {$Define ln:=+ LineEnding}
  3. const
  4.   mls = 'multi'ln +
  5.         'line'ln +
  6.         'string';
[... etc ...]
A hint, if I may: better shut off macros or undefine "ln" when it's no longer needed; otherwise you might find all your WriteLn()'s converted to "Write+LineEnding()" ;D

ETA: In case somone takes it seriously: The compiler won't really do that; it was just to illustrate one drawback of using macros a la brava.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 28, 2020, 01:06:54 am
Lazarus editor also provides an easy way to paste multiline string -- right click in place where you want to insert it and chose "Multi paste" (not actually a self-explaining name for that option).

For example, type this, select it and copy to clipboard:
Quote
select
  p.proj_id,
  case when p.team_leader = e.emp_no then 'project leader' else '' end as is_leader,
  e.full_name,
  p.proj_name, p.proj_desc, p.product
from project p
inner join employee_project ep on ep.proj_id = p.proj_id
inner join employee e on e.emp_no = ep.emp_no
order by 1, 2 desc

And then right-click to where you want it, chose Multi paste, and we can do this:

(see four steps in attached images)

After that, you only have to delete the first '+ LineEnding +'.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Martin_fr on December 28, 2020, 01:22:07 am
Lazarus editor also provides an easy way to paste multiline string -- right click in place where you want to insert it and chose "Multi paste" (not actually a self-explaining name for that option).

Further more, if you are entering a string and hit enter while still inside the string (no closing ' yet) then you can configure the editor ("tab and indent") to insert the closing ' and any text you want.
E.g.
Code: Pascal  [Select][+][-]
  1. ' + LineEnding +

If you also want to be able to join lines and do other edit ops, you can always write editor macros (using Pascal Script) to detect your personal line break style and act on it.
A macro can also change the Pascal strings into raw text.

The difference is, that you will see the LineEnding in the source. But that also means you will see what line-ending it actually is: hardcode #13 or #10 or #13#10 or target specific LineEnding.
And you can also choose which of those line-endings you want to use.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 28, 2020, 01:34:36 am
Lots of ways, for example:
  • use a resourcestring section, though that posses the same problem with multi-line strings as any other code;
  • go down to basics and write your strings in an rc script as a string table, reading them back with a TStringTableResource, which has the advantage than some (most?) resource compilers allow you to use C-like scapes in the rc script;
  • ... etc ...
Ok well I know those ways but they are not really making it simpler.

Lazarus editor also provides an easy way to paste multiline string -- right click in place where you want to insert it and chose "Multi paste" (not actually a self-explaining name for that option).
That's good to know. In a way that solves the question.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: 440bx on December 28, 2020, 02:04:13 am
That's good to know. In a way that solves the question.
A few things are worth noting...

Yes, the feature saves some typing and/or the multi-line steps but...

Comparing the example @Zoran posted (see previous page) which uses "+ LineEnding" with using the backtick (see https://forum.lazarus.freepascal.org/index.php/topic,46050.msg326901.html#msg326901), the result using the backtick method proposed by @Akira1364 is substantially cleaner and easier to read, specifically because there are no "+" and "LineEnding" poking the eye of the reader.  In addition to that, changing the text is much simpler because the programmer doesn't have to concern him/herself with possibly having to add or delete "+ LineEnding".

IOW, the savings in typing are a bonus, what's nice about the feature is how much cleaner the resulting code is.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lucamar on December 28, 2020, 02:47:19 am
Comparing the example @Zoran posted (see previous page) which uses "+ LineEnding" with using the backtick (see https://forum.lazarus.freepascal.org/index.php/topic,46050.msg326901.html#msg326901), the result using the backtick method proposed by @Akira1364 is substantially cleaner and easier to read, specifically because there are no "+" and "LineEnding" poking the eye of the reader.  In addition to that, changing the text is much simpler because the programmer doesn't have to concern him/herself with possibly having to add or delete "+ LineEnding".

On the other hand, the "backtick" is a small glyph and somewhat difficult to see when you're eye-scanning the text and making modifications at three a.m. and you are looking through a mental fog and irritated, tear-strained eyes.
I'd vote for a more visually apealling symbol, like the double-quote ... just saying :-\
Title: Re: Idea of multi-line strings, mantis 35827
Post by: 440bx on December 28, 2020, 03:12:38 am
On the other hand, the "backtick" is a small glyph and somewhat difficult to see when you're eye-scanning the text and making modifications at three a.m. and you are looking through a mental fog and irritated, tear-strained eyes.
That's true and, it is likely a significant reason why the code looks so clean.  Everything has its pros and cons, backtick included.  ;)
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Warfley on December 28, 2020, 04:07:35 am
https://bugs.freepascal.org/view.php?id=35827
I only want to suggest a syntax for multi-line strings:

case1)

Code: Pascal  [Select][+][-]
  1. var s = 'begin'/
  2. 'mdl'/
  3. 'end.' ;

Here we use / which is not defined for strings.
One thing I just rembered, if runtime code is not a problem (which it is for like consts), the following works:
Code: Pascal  [Select][+][-]
  1. operator /(const lhs: String; const rhs: String): String;
  2. begin
  3.   Result := lhs + LineEnding + rhs;
  4. end;
  5.  
  6. var
  7.   s: String;
  8. begin
  9.   s := 'foo' /
  10.        'bar';
  11.   WriteLn(s);
  12. end;

But thats not a good solution. Also I think / is not the best symbol, rather _ or something completely different like a named operator.

A hint, if I may: better shut off macros or undefine "ln" when it's no longer needed; otherwise you might find all your WriteLn()'s converted to "Write+LineEnding()" ;D
This was more of an example, if one thinks this more through, probably ln is also not the best name (probably a lot of people including me use ln as name for temporary variables containing lines). Something that is highly unlikely to be used, maybe something starting or ending on underscore, something line "_ln" or "_endl" or so.
Then this does not need to be undeffed necessarily.

But yeah, macros can be very messy, it has a reason why, unlike to C or C++ in pascal they are deactivated by default. A real, language level solution would be great. But as long as we don't have it, I personally think this produces much cleaner code than "+ LineEnding", which makes the code really ugly
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Leledumbo on December 28, 2020, 04:52:11 am
But thats not a good solution.
Not a bad one either to me. At least it serves the purpose, other overloadable symbolic operators are only - and *, which is way worse than /, while the rest are identifier operators. Nah, I wouldn't define AND for it.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Awkward on December 28, 2020, 06:50:13 am
... or we can just use double-plus ++ ...
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lucamar on December 28, 2020, 07:24:34 am
A good solution should also work for constants and ressource strings; an operator overload won't do that because it's not active at compile-time.

In fact, now I think about it, are you sure this works?:
Code: Pascal  [Select][+][-]
  1. var
  2.   s: String;
  3. { ...}
  4.   s := 'foo' /
  5.        'bar';
because I remember having tested (again) some time this year and operator overloads ("*" in my case) didn't work when dealing with constants, even if assigning them to a var (IIRC, which I might not; it was in spring or early summer).
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 28, 2020, 10:04:01 am
the backtick method proposed by @Akira1364 is substantially cleaner and easier to read,

On contrary, it introduces something very dirty to Pascal language -- significant whitespaces at the end of line.
Inside these multiline strings, it is not obvious where the line ends. It is a very dirty feature.

In a language which should have clean syntax, you should safely rely on that there cannot be significant whitespaces at the end of a line.

With multiline string, you don't see where a line actually ends. You have to check it, and in Lazarus editor, as it is now, even that checking is not so easy -- the caret can be put anywhere beyond the actual end of the line.
So, with multiline strings, Lazarus editor will need to remove this feature. And it is a very nice feature -- I wouldn't like the caret to go left-right when I am going up-down through code.

Another beautiful feature which the editor will have to remove is automatically removing spaces from line endings when saving the unit file.

The editor uses the fact that in Pascal, spaces at the end of the line are always insignificant.
And the programmer should always be able to safely rely on that.

Some other languages do not care that much about clean syntax. In Pascal, clean syntax has always been important.
So, please do not introduce significant whitespaces at line endings in Pascal.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: wp on December 28, 2020, 10:13:09 am
So, please do not introduce significant whitespaces at line endings in Pascal.
+1
Title: Re: Idea of multi-line strings, mantis 35827
Post by: marcov on December 28, 2020, 11:56:27 am
Better load them from resources, easier to post compilation translate them
How would you do that actually?

I don't do much enduser ready stuff in Lazarus, mostly internal tooling. But in my companies main (Delphi) app, I edit everything with GORM (poedit equivalemet made in Delphi), and then embed the .po's into the binary.

But the internal PO's can be overriden by external POs.   I use this for all user visible strings.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 28, 2020, 12:17:21 pm
I don't do much enduser ready stuff in Lazarus, mostly internal tooling. But in my companies main (Delphi) app, I edit everything with GORM (poedit equivalemet made in Delphi), and then embed the .po's into the binary.
Ok. Interesting, though that doesn't make it easier to add multiline strings, does it? You still need to add them as string constant.

So, please do not introduce significant whitespaces at line endings in Pascal.
+1
I suppose we can say the lines are R-trimmed.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: PascalDragon on December 28, 2020, 01:14:37 pm
All this stuff was already discussed in the thread (https://forum.lazarus.freepascal.org/index.php/topic,46050.0.html) by Akira1364 about this functionality. There won't be any further changes in syntax, cause it's good enough as it is and the majority of the core devs agree with it.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: marcov on December 28, 2020, 01:30:11 pm
I don't do much enduser ready stuff in Lazarus, mostly internal tooling. But in my companies main (Delphi) app, I edit everything with GORM (poedit equivalemet made in Delphi), and then embed the .po's into the binary.
Ok. Interesting, though that doesn't make it easier to add multiline strings, does it?

You edit them in a memo? How much easier can it get?

Quote
You still need to add them as string constant.

No you load them by constant name/key from the compiled .po (.mo).

Title: Re: Idea of multi-line strings, mantis 35827
Post by: circular on December 28, 2020, 01:55:57 pm
No you load them by constant name/key from the compiled .po (.mo).
Oh ok, that sounds convenient. Is there a tutorial on that?
Title: Re: Idea of multi-line strings, mantis 35827
Post by: 440bx on December 28, 2020, 02:08:39 pm
On contrary, it introduces something very dirty to Pascal language -- significant whitespaces at the end of line.
Inside these multiline strings, it is not obvious where the line ends. It is a very dirty feature.

<snip>

So, please do not introduce significant whitespaces at line endings in Pascal.
But that supposes that Akira's proposal is a replacement for what is already in the language and that is simply not the case.

The multi-line string proposal is a feature that does a great job in _some_ cases.  As such, just like all Pascal features, it should be used for the problem it solves, e.g, multi-line strings such as embedded SQL commands.  There are cases when it is _not_ the right solution, that doesn't mean it "dirties" the language. 

It isn't about where the line ends, what's important is that the feature matches the visual structure of a string to its function, i.e, one or more spaces or newlines will be present where they are expected while removing visual clutter that obfuscates what the resulting string should be.

Title: Re: Idea of multi-line strings, mantis 35827
Post by: Martin_fr on December 28, 2020, 02:33:11 pm
multi-line strings such as embedded SQL commands.  There are cases when it is _not_ the right solution, that doesn't mean it "dirties" the language. 

But SQL commands do not need linefeeds in the text (they can have, but do not need).

So the gain is minimal
Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar '+
  2.        'from t1 '+
  3.        'where foo > bar';

It really is just 3 chars per line ',',+
And they can be inserted by the IDE when you first write the sql.
The only bother is in the very few cases where you drastically shorten the sql and want to join lines.

Title: Re: Idea of multi-line strings, mantis 35827
Post by: Martin_fr on December 28, 2020, 02:44:46 pm
Most examples show only the least intrusive side of the multiline string.  (As a constant declaration)

But they can occur anywhere in the code too (using ` in the example)
Code: Pascal  [Select][+][-]
  1.   if (DataLineRetrieved = `Lorem ipsum dolor
  2.  sit amet, consectetur adipiscing elit,
  3.  sed do eiusmod tempor incididunt
  4.  ut labore et dolore magna aliqua.`) and
  5.      (NextLineToSend = `Ut enim ad minim
  6.  veniam, quis nostrud exercitation
  7.  ullamco laboris nisi ut aliquip ex ea
  8.  commodo consequat.`) then
  9.   begin
  10.     DoSomething(`Lorem ipsum dolor `, `sit amet, consectetur
  11.  adipiscing elit, sed do eiusmod`, ` tempor incididunt
  12.  ut labore et dolore
  13.  magna aliqua. `, `Ut enim ad minim veniam, `, `quis
  14.  nostrud exercitation ullamco
  15.  laboris nisi ut aliquip ex ea commodo consequat.`);
  16.   end;
  17.  

And save yourself the repeated "But you do not have to use it that way". The day will come where any of us will have to decipher something like this.

And how much fun, if the `` were to contain a lengthy fragment of Pascal source... (maybe even with embedded escaped ` inside)
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 28, 2020, 04:29:24 pm
But that supposes that Akira's proposal is a replacement for what is already in the language and that is simply not the case.

It means that you no more can rely on that Pascal source file cannot have significant white space characters at the end of line.

In this topic I already mentioned two Lazarus' code editor's great features which rely on this:
- Trimming of white spaces from the line endings when saving. If multiline strings get into language, this feature will have to be removed unless made smarter - to first parses the code to determine if the line belongs to some string.
- Caret can be put anywhere beyond the end of line, behaving as if there are indefinite spaces there -- I find it very convenient when moving up-down through code, but it relies on that you should never care if there are spaces or not.


And save yourself the repeated "But you do not have to use it that way". The day will come where any of us will have to decipher something like this.

Of course, you cannot turn off the feature, as I said in another topic, saying "if you don't like this feature, you don't have to use it" is just very wrong.
It's wrong for the reasons I gave there:

I think,nobody is forced to use inline variables in C++.

Please never use this argument.
Programming is not only writing new code, but also reading and understanding code written by others.
And in the end it is much more maintaining (often other people's) code, than writing new code.

This is not about "inline variables", but generally, saying "if you don't like this feature, you don't have to use it" is just very wrong.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: 440bx on December 28, 2020, 07:00:56 pm
But SQL commands do not need linefeeds in the text (they can have, but do not need).
As your statement above clearly indicates, the presence or absence of a line feed in that case makes no difference.  Therefore the solution that produces the less clutter is preferable.

So the gain is minimal
Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar '+
  2.        'from t1 '+
  3.        'where foo > bar';

It really is just 3 chars per line ',',+
It's more than that.  Using your example and using Akira's multi-line strings, that can be rewritten as:
Code: Pascal  [Select][+][-]
  1. sql := '
  2.         select foo, bar
  3.         from t1
  4.         where foo > bar
  5.        ';
Not only is that easier to read, additions can be made without being encumbered with ' and + thereby lowering the possibility of errors.

And they can be inserted by the IDE when you first write the sql.
The IDE cannot achieve the above which is, increasing legibility and lowering the inclusion of errors during maintenance. 

The only bother is in the very few cases where you drastically shorten the sql and want to join lines.
The "bother" is when the sql statements need to be modified.  The multi-line string facility makes that easier and less prone to errors.

Another example using your own post:
Code: Pascal  [Select][+][-]
  1.   if (DataLineRetrieved = `Lorem ipsum dolor
  2.                            sit amet, consectetur adipiscing elit,
  3.                            sed do eiusmod tempor incididunt
  4.                            ut labore et dolore magna aliqua.`
  5.      ) and
  6.      (NextLineToSend =    `Ut enim ad minim
  7.                            veniam, quis nostrud exercitation
  8.                            ullamco laboris nisi ut aliquip ex ea
  9.                            commodo consequat.`
  10.     ) then
  11.     begin
  12.        DoSomething(`Lorem ipsum dolor `,
  13.                     `sit amet, consectetur
  14.                      adipiscing elit, sed do eiusmod`,
  15.                     ` tempor incididunt
  16.                       ut labore et dolore
  17.                       magna aliqua. `,
  18.                     `Ut enim ad minim veniam, `,
  19.                     `quis
  20.                      nostrud exercitation ullamco
  21.                      laboris nisi ut aliquip ex ea commodo consequat.`);
  22.   end;
  23.  
The code above is much more readable and easier to maintain.  That said, your example is also contrived.  It is rare to perform operations on multi-line strings and, it could be one of those cases where using the "+" and LineEnd may be justified.

And how much fun, if the `` were to contain a lengthy fragment of Pascal source... (maybe even with embedded escaped ` inside)
Sounds more like that would be an ideal use of the multi-line string facility.  The code could simply be copied and pasted between two backticks.  Much simpler than tediously adding "+" and LineEnd at the end of every line of code.



It means that you no more can rely on that Pascal source file cannot have significant white space characters at the end of line.
multi-line strings don't introduce significant white space at the end of the line.  The line end itself acts as a separator as it always has.

saying "if you don't like this feature, you don't have to use it" is just very wrong.
nice sound bite but, how do you justify that claim ?  IOW, what is wrong about deciding _not_ to use a feature in the language ?  just because a feature is present, it doesn't mean it _has_ to be used.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 28, 2020, 07:19:36 pm
Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar '+
  2.        'from t1 '+
  3.        'where foo > bar';
  4.  
It really is just 3 chars per line ',',+

Elsewhere, there's currently discussion about these lines in FPC

Code: Pascal  [Select][+][-]
  1.       msg_errorparsingparametersatpos = ^C'Error parsing parameters line at line position %d.';
  2.       msg_cantinstallmoretools = ^C'Can''t install more tools...';
  3.  

which we're told parse the same as

Code: Pascal  [Select][+][-]
  1.       msg_errorparsingparametersatpos = Chr(3) + 'Error parsing parameters line at line position %d.';
  2.       msg_cantinstallmoretools = Chr(3) + 'Can''t install more tools...';
  3.  

Hence if concatenation really is implicit your example becomes the even less arduous

Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar '
  2.        'from t1 '
  3.        'where foo > bar';
  4.  

MarkMLl

Title: Re: Idea of multi-line strings, mantis 35827
Post by: Martin_fr on December 28, 2020, 07:43:02 pm
But SQL commands do not need linefeeds in the text (they can have, but do not need).
As your statement above clearly indicates, the presence or absence of a line feed in that case makes no difference.  Therefore the solution that produces the less clutter is preferable.
IMHO, that is terminating each string on its own line. ;)
For example it makes leading/trailing whitespace more apparent. I do not need to look out, what the compiler may have been told to do with them and what not. (Not that they matter for SQL)


Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar '+
  2.        'from t1 '+
  3.        'where foo > bar';
It really is just 3 chars per line ',',+
And they can be inserted by the IDE when you first write the sql.
The IDE cannot achieve the above which is, increasing legibility and lowering the inclusion of errors during maintenance. 
Code: Pascal  [Select][+][-]
  1. sql := 'select foo, bar
The IDE can be configured so that - upon pressing enter - it will insert
Code: Pascal  [Select][+][-]
  1. ' +
  2.  '
and place the caret.


The only bother is in the very few cases where you drastically shorten the sql and want to join lines.
The "bother" is when the sql statements need to be modified.  The multi-line string facility makes that easier and less prone to errors.
I do read both of our statements the same.
At least with SQL, I find it (in my own experience) rather rare that I need to join 2 existing lines.
Usually its add or remove lines. Add/Remove is easy to do with quotes per line.

I do not dispute that it saves (up to?) 2 or 3 keypresses (per line). But are those worth the potential downsides? Other things that would have saved many more keystrokes have been rejected as syntactical sugar (and rightfully so).

Mind also: In the above, I merely reject the "sql" example, as an example for multiline strings. IHMO the sql example does not show any real meaningful savings.


Code: Pascal  [Select][+][-]
  1.   if (DataLineRetrieved = `Lorem ipsum dolor
  2. ...
The code above is much more readable and easier to maintain.  That said, your example is also contrived.  It is rare to perform operations on multi-line strings and, it could be one of those cases where using the "+" and LineEnd may be justified.
"That said, your example is also contrived"
Exactly. Or rather, as of now: Exactly.

Luckily, the current string syntax discourage such abhorrent usage. Multiline strings will make this easier to write, and more likely to happen.


And how much fun, if the `` were to contain a lengthy fragment of Pascal source... (maybe even with embedded escaped ` inside)
Sounds more like that would be an ideal use of the multi-line string facility.  The code could simply be copied and pasted between two backticks.  Much simpler than tediously adding "+" and LineEnd at the end of every line of code.
Why not have it in its own file, added as resource. Much more flexible.

Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 28, 2020, 08:29:29 pm
It means that you no more can rely on that Pascal source file cannot have significant white space characters at the end of line.
multi-line strings don't introduce significant white space at the end of the line.  The line end itself acts as a separator as it always has.

You mean that the string like this:
Code: Pascal  [Select][+][-]
  1. 'abcd   ' + LineEnding + 'efgh' // has spaces in the first line
will not be possible to represent in new multiline form?

saying "if you don't like this feature, you don't have to use it" is just very wrong.
nice sound bite but, how do you justify that claim ?  IOW, what is wrong about deciding _not_ to use a feature in the language ?  just because a feature is present, it doesn't mean it _has_ to be used.

As I said, I justify that claim with what I said in the other thread (https://forum.lazarus.freepascal.org/index.php/topic,42271.msg387933.html#msg387933).
Please read again my post above, including the post I not only linked to, but quoted there.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: 440bx on December 28, 2020, 09:18:54 pm
IMHO, that is terminating each string on its own line. ;)
I believe you are right about that.  I don't see a problem with it whenever having a string on its own line doesn't affect the semantics, as is the case in an SQL statement (as you pointed out too.)

The IDE can be configured so that - upon pressing enter - it will insert
Code: Pascal  [Select][+][-]
  1. ' +
  2.  '
and place the caret.
That's not a very desirable solution.  the IDE has to be configured to do it (that requires work) and adding those characters upon pressing <enter> isn't always desired.  In addition to that, whether those characters are inserted automatically or not, they still clutter text.  IOW, in the best case, the IDE can provide a limited amount of help (I'd say even calling it help is questionable) yet still be unable to really increase the legibility.



Usually its add or remove lines. Add/Remove is easy to do with quotes per line.
True but, it's even easier if quotes are not needed.

I do not dispute that it saves (up to?) 2 or 3 keypresses (per line). But are those worth the potential downsides? Other things that would have saved many more keystrokes have been rejected as syntactical sugar (and rightfully so).
My position on that feature is _not_ based on saving keystrokes (I'm not afraid of typing a lot), I support that feature because when used appropriately it results in greater readability and increase ease of maintenance.  That's more than syntactic sugar.


Mind also: In the above, I merely reject the "sql" example, as an example for multiline strings. IHMO the sql example does not show any real meaningful savings.
The statement is much cleaner and easier to read.  IMO, that's a meaningful improvement particularly considering that in a program that does a lot of database access, the improvement will take place in every SQL statement.   As they say in the U.S Congress, a billion here, a billion there and pretty soon, you're talking about real money.


Luckily, the current string syntax discourage such abhorrent usage. Multiline strings will make this easier to write, and more likely to happen.
it will be a good day for programming when the most abhorrent thing seen in a program is the misuse of the multi-line string feature. 

Why not have it in its own file, added as resource. Much more flexible.
Not really sure if that is more flexible.  Another file to manage and, all the statements are in a "big bucket" instead of being defined where they are needed, i.e, no context locality.



You mean that the string like this:
Code: Pascal  [Select][+][-]
  1. 'abcd   ' + LineEnding + 'efgh' // has spaces in the first line
will not be possible to represent in new multiline form?
I believe that to be correct that such a line could not be represented using Akira's mult-line string feature.   That said, that's an "educated guess" on my part.  Akira could authoritatively answer your question.



As I said, I justify that claim with what I said in the other thread (https://forum.lazarus.freepascal.org/index.php/topic,42271.msg387933.html#msg387933).
Please read again my post above, including the post I not only linked to, but quoted there.
I did and, as far as reading and understanding other people's code, the less cluttered the code is, the easier it is to read and understand.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 28, 2020, 09:47:25 pm
Why not have it in its own file, added as resource. Much more flexible.

Quite frankly the place for SQL is inline with the code that provides parameters and parses the result.

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Martin_fr on December 28, 2020, 10:28:01 pm
Why not have it in its own file, added as resource. Much more flexible.

Quite frankly the place for SQL is inline with the code that provides parameters and parses the result.

MarkMLl
The original statement here was not related to SQL. (It was about inlining other source code as text)
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 29, 2020, 12:20:15 am
You mean that the string like this:
Code: Pascal  [Select][+][-]
  1. 'abcd   ' + LineEnding + 'efgh' // has spaces in the first line
will not be possible to represent in new multiline form?
I believe that to be correct that such a line could not be represented using Akira's mult-line string feature.   That said, that's an "educated guess" on my part.  Akira could authoritatively answer your question.

If so, I'm not against it. For me, that was the fundamental problem with it.
Okay, I still wouldn't need it, but I would not oppose it.
But I doubt it is so. Restricting its usage to only text whose lines cannot end with spaces is hardly the idea.

As I said, I justify that claim with what I said in the other thread (https://forum.lazarus.freepascal.org/index.php/topic,42271.msg387933.html#msg387933).
Please read again my post above, including the post I not only linked to, but quoted there.
I did and, as far as reading and understanding other people's code, the less cluttered the code is, the easier it is to read and understand.

You asked me with what I justified the claim that the argument "Just do not use it if you don't like it" is never valid when talking about language features.
To that question I answered, there I did not comment whether it is more readable or not.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lainz on December 29, 2020, 02:56:57 am
In my opinion the multi line string is really good.

But as well there is the interpolation feature to add variables inside.

Var myint:integer;

...

Mystring := """my age
                         is $myint""".trimmwhitespace()

Prints

my age
is 31

And about leading whitespace in kotlin there is a method to remove whitespace from left and right
Title: Re: Idea of multi-line strings, mantis 35827
Post by: PascalDragon on December 29, 2020, 11:37:51 am
But as well there is the interpolation feature to add variables inside.

Definitely no.

There better be a switch to turn this OFF!

The multiline string feature is coupled to a modeswitch that's off by default.

But even then: the feature being enabled won't affect your code in any way if you don't use it. And you can't do anything against third party developers that do use the feature and where you use these units (as modeswitches are per-unit).
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lainz on December 29, 2020, 04:03:38 pm
But as well there is the interpolation feature to add variables inside.

Definitely no.

I know, I already know, always I get that response from FPC.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Zoran on December 29, 2020, 05:03:16 pm
And about leading whitespace in kotlin there is a method to remove whitespace from left and right

What do you mean?

There are functions in fpc as well (in SysUtils - Trim, TrimLeft, TrimRight (https://www.freepascal.org/docs-html/current/rtl/sysutils/trim.html), which are also provided as String helper routines (https://www.freepascal.org/docs-html/current/rtl/sysutils/tstringhelper.trimleft.html)). Plus, with LazUtils dependecy, in LazUTF8 unit there is UTF8Trim (https://lazarus-ccr.sourceforge.io/docs/lazutils/lazutf8/utf8trim.html) function with more possibilities...
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lainz on December 29, 2020, 05:32:06 pm
And about leading whitespace in kotlin there is a method to remove whitespace from left and right

What do you mean?

There are functions in fpc as well (in SysUtils - Trim, TrimLeft, TrimRight (https://www.freepascal.org/docs-html/current/rtl/sysutils/trim.html), which are also provided as String helper routines (https://www.freepascal.org/docs-html/current/rtl/sysutils/tstringhelper.trimleft.html)). Plus, with LazUtils dependecy, in LazUTF8 unit there is UTF8Trim (https://lazarus-ccr.sourceforge.io/docs/lazutils/lazutf8/utf8trim.html) function with more possibilities...

I mean this
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-indent.html
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Warfley on December 29, 2020, 09:56:22 pm
I mean this
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-indent.html
This is not possible in Pascal due to the strict runtime and compiletime separation, which Kotlin simply does not have.

There can't be runtime code in the declaration section. Example:
Code: Pascal  [Select][+][-]
  1. const
  2.   s_const = 'foo'.Trim; // does not work, the expression here must be a compile time expression
  3.   s_static: String = 'foo'.Trim; // does not work, the expression here must be a compile time expression
  4. var
  5.   s: String = 'foo'.Trim; // does not work, the expression here must be a compile time expression
  6. begin
  7.   s := 'foo'.Trim; // works
  8. end.
To use runtime code, like a Trim function, you need to in the implementation block of your function, program, whatever and not in the definition block (where variables, constants, etc. are defined).

Kotlin does not have such a limiation, Kotlin can execute anything anywhere.

The only possible solution on how to build something like this would be to make trim a compiler intrinsic like sizeof. Or one could just restrict himself to using runtime constructs and don't use that in constants or as initial value for variables. But honestly I think that multiline strings are most useful in constants, so this does not seem like a good solution
Title: Re: Idea of multi-line strings, mantis 35827
Post by: lainz on December 29, 2020, 11:42:44 pm
I see, thanks for the clarification.

So must be an intrinsic trim, and another trimIndent that does different things. One is for a single line, and other for multi lines.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 30, 2020, 11:21:53 am
To use runtime code, like a Trim function, you need to in the implementation block of your function, program, whatever and not in the definition block (where variables, constants, etc. are defined).

Allowing types to have attributes e.g. "is trimmed on assignment" would probably fix this, but unless the language were completely reengineered to be extensible they'd have to be agreed on in advance.

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Warfley on December 30, 2020, 07:04:44 pm
Allowing types to have attributes e.g. "is trimmed on assignment" would probably fix this, but unless the language were completely reengineered to be extensible they'd have to be agreed on in advance.
Yeah, I mean compiler magic is always a solution that could be implemented, but I think such things are way to specific to justify having custom compiler makros or so for them. A more general approach, used in other languages like Java, is the defining of custom annotations that influence the code generation during compiletime. E.g.
Code: Java  [Select][+][-]
  1. @Getter @Setter
  2. private String myString;
From the Lombok package automatically generates setMyString and getMyString methods. These can be defined in Java, which is executed during compiletime.

Something like this could allow for defining custom attributes that will be executed during compiletime.

Another option would be compiletime functions. C++ allows for constexpr functions, these are functions of whoom all inputs are constants available during compiletime, that will be evaluated during compiletime. A constexpr TrimIndent could there be implemented that way.

But to be honest, Pascal is probably not the kind of language where such features are going to be implemented. While they can be very neat with regards to usability (like the getter and setter example from above), they add a whole new dimension to the language, where the behavior of every line of code can be completely altered with such annotations, which need to be understood by the maintainer in the first place (and looking at some enterprise Java source, these annotations can look like black magic).

Something that might be more interesting would be if runtime code could be used in the definition segment. I think the ugliest part of pascal that always create really bad code is the use of the initialization and finalization segment.
Very often I use this segment to initialize global variables, like loggers or something like this. This means the logger is defined somewhere in the middle of the file, but the initialization code is at the very bottom, often like 500 lines or more away from the definition of the data the code relates to.
I think there could be a usefull alternative, something like:
Code: Pascal  [Select][+][-]
  1. var
  2.   MyLogger: TLogger initialize MyLogger := TLogger.Create(Output) finalize MyLogger.Free;
with a multiline alternative:
Code: Pascal  [Select][+][-]
  1. var
  2.   MyLogger: TLogger initialize
  3.   begin
  4.     SetConsoleOutputCP(DefaultSystemCodePage);
  5.     SetTextCodePage(Output, DefaultSystemCodePage);
  6.     MyLogger := TLogger.Create(Output);
  7.   end
  8.   finalize
  9.     MyLogger.Free;

In that case the trimming could be done with something like that:
Code: Pascal  [Select][+][-]
  1. var
  2.   mls: String initialize mls := 'foo '.Trim;

But this is just an idea I had some time ago because I really hate the way the initialization and finalization segments work currently.

PS: if we only consider runtime code, one way to handle something like this would be a wrapper type:
Code: Pascal  [Select][+][-]
  1.   { TTrimmedString }
  2.  
  3.   TTrimmedString = record
  4.   private
  5.     Data: String;
  6.   public
  7.     class operator :=(const src: String): TTrimmedString;
  8.     class operator :=(const src: TTrimmedString): String;
  9.   end;
  10.  
  11. { TTrimmedString }
  12.  
  13. class operator TTrimmedString.:=(const src: String): TTrimmedString;
  14. begin
  15.   Result.Data:=src.Trim;
  16. end;
  17.  
  18. class operator TTrimmedString.:=(const src: TTrimmedString): String;
  19. begin
  20.   Result := src.Data;
  21. end;
  22.  
  23. var
  24.   s: TTrimmedString;
  25. begin
  26.   s := '42 ';
  27.   Write(StrToInt(s)); // can be used for any string implicetly
  28.   ReadLn;
  29. end.
But again this is restricted to runtime code only
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on December 30, 2020, 07:31:19 pm
Code: Pascal  [Select][+][-]
  1. var
  2.   MyLogger: TLogger initialize MyLogger := TLogger.Create(Output) finalize MyLogger.Free;

It strikes me that that is not a million miles from the deferred code generation currently being used for templates.

But if a language has to do that sort of thing it's possibly time for a "delete all and insert".

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: PascalDragon on December 31, 2020, 04:24:18 pm
Another option would be compiletime functions. C++ allows for constexpr functions, these are functions of whoom all inputs are constants available during compiletime, that will be evaluated during compiletime. A constexpr TrimIndent could there be implemented that way.

But to be honest, Pascal is probably not the kind of language where such features are going to be implemented. While they can be very neat with regards to usability (like the getter and setter example from above), they add a whole new dimension to the language, where the behavior of every line of code can be completely altered with such annotations, which need to be understood by the maintainer in the first place (and looking at some enterprise Java source, these annotations can look like black magic).

J. Gareth Moreton is working on a concept called pure functions which is essentially constexpr for Pascal.

Something that might be more interesting would be if runtime code could be used in the definition segment. I think the ugliest part of pascal that always create really bad code is the use of the initialization and finalization segment.

No. With this you're mixing declarations and code, something that we're already against with Delphi's inline variables and this would simply be the other way round.
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Warfley on January 02, 2021, 08:56:15 pm
No. With this you're mixing declarations and code, something that we're already against with Delphi's inline variables and this would simply be the other way round.
But then the question arises, is a strict distinction between declaration and code a good thing in this circumstance. Because I don't see any value in purism just for purisms sake. Just because in some circumstances this distinction produces better code, does not mean that in all circumstances it does and should be enforced in all circumstances. If it produces worse code, there is no reason to enforce this.

For example with inline variabes, this makes absolutely sense, because when you read code, and you see a variable, and you want to check what it is, having one region where all the variables are declared makes sense. Also inside your function there is usually only 1 region where variables are declared and only one region where the code is written. So you clearly know where you find the variables and where the code is. This is why for example a lot of C coding guidelines say that non loop variables should be declared at the start of the function.

For global variables this line of reasoning does not work, because global variables can be declared anywhere in a document.
You can have this:
Code: Pascal  [Select][+][-]
  1. procedure Foo;
  2. ...
  3. var
  4.   var1: TMyClass;
  5. procedure Bar;
  6. ...
  7. const
  8.   const1 = 'foo';
  9. type
  10.   TFoo = class
  11.   ...
  12.     procedure Foo;
  13.   end;
  14. var
  15.   var2: String;
  16. procedure TFoo.Foo;
  17. ...
  18.  
  19. function GetVar1: TMyClass;
  20. begin
  21.   if not Assigned(var1) then
  22.     var1 := TMyClass.Create;
  23.   Result := Var1;
  24. end;
  25.  
  26. initialization
  27.   var2 := const1;
  28. end.
Here just to find out what var2 and const1 actually is, you need to spot that single line between types and function definitions. Also the initialization does not need to happen in the initialization part, but for example with singletons are usually created when their getter is first called, as shown here with GetVar1.

So if you see a global variable anywhere in the document, you need to scroll all the way down to see if and how it get's initialized, and if you see the usage of a global variable in the initialization or finalization section, you need to search the whole document where it is declared.
This is the exactly the issue that is solved by the distinction of code and declaration on the function level, that is caused by this very same distinction on the unit level.

With the coupeling of inizialization and finalization at the declaration point this would be not an issue. When you see a global variable you instantly see how it is initialized and finalized. Also it solves the dependency issue, because without it you need to initialize and finalize in the correct order if the initialization and finalization depends on other global variables. With the direct initialization the compiler can simply build a dependency graph during compiletime and solve the dependency issue algorithmically without the user having to think about it

J. Gareth Moreton is working on a concept called pure functions which is essentially constexpr for Pascal.
This is great news. With the not so pascallian I meant more like the java like annotations. Because they always look like black magic to me, and I hope something like this never comes to pascal
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Blade on September 18, 2021, 03:46:48 am
It's more than that.  Using your example and using Akira's multi-line strings, that can be rewritten as:
Code: Pascal  [Select][+][-]
  1. sql := '
  2.         select foo, bar
  3.         from t1
  4.         where foo > bar
  5.        ';
Not only is that easier to read, additions can be made without being encumbered with ' and + thereby lowering the possibility of errors.

I agree with this concept.  What should be avoided is having to add something line by line, versus simply being able to paste some text.  Looks like a matter of just agreeing on something distinct.  I would like to see something like below.

Code: Pascal  [Select][+][-]
  1. sql := '(
  2.         select foo, bar
  3.         from t1
  4.         where foo > bar
  5.         )';
  6.  
Title: Re: Idea of multi-line strings, mantis 35827
Post by: MarkMLl on September 18, 2021, 09:25:57 am
I agree with this concept.  What should be avoided is having to add something line by line, versus simply being able to paste some text.  Looks like a matter of just agreeing on something distinct.  I would like to see something like below.

I'm somewhat dubious, since generally speaking languages which allow things like "here-documents" do so at a preprocessor stage rather than as an integral part of the syntax.

An alternative would be to leave single-quoted strings alone, since this is the majority usage and checking that strings are properly terminated (i.e. on the same line) is valuable.

Instead, define a double-quoted string as operating on multiple lines, but make := " into a special redefinable operator so that the semantics of the quoted text don't have to be locked-down by the compiler and those used to backslash escapes etc. can use them.

MarkMLl
Title: Re: Idea of multi-line strings, mantis 35827
Post by: Jurassic Pork on September 18, 2021, 02:34:37 pm
hello,
you can also use the macro editor in the ide with a shortcut to launch the formatting string line function (written in pascalscript) on the selected text.
see demo in attachment (click on the image to see animation).

Friendly, J.P
TinyPortal © 2005-2018