Recent

Author Topic: String Type Helper Join  (Read 3442 times)

WayneSherman

  • Full Member
  • ***
  • Posts: 243
String Type Helper Join
« on: May 01, 2022, 05:36:00 pm »
I was trying to join strings using helpers and discovered that the value of the string is completely ignored:

Code: Pascal  [Select][+][-]
  1. AString := 'C:';
  2. //none of these work correctly
  3. AString.Join('\', ['Windows', 'System32']);  //this doesn't do anything
  4. AString := AString.Join('\', ['Windows', 'System32']); //this misses the 'C:', i.e. the contents of AString is ignored
  5. AString := AString + AString.Join('\', ['Windows','System32']); //this doesn't use the separator on the first concatentation.
  6.  
  7. //This works, but ugly
  8. AString := 'C:';
  9. AString := AString + '\' + AString.Join('\', ['Windows', 'System32']);
  10.  
  11. //or maybe this one is the best way
  12. AString := AString.Join('\', [AString, 'Windows', 'System32']);

Also, it would be nice to have a "PathJoin" helper which automatically uses the correct OS path separator and normalizes the path to remove double separators and fix wrong separators:

Code: Pascal  [Select][+][-]
  1. AString := 'C:\Windows\';
  2. AString := AString.PathJoin(['\system32\', '/drivers/', 'etc', 'hosts']);
  3. // on Windows gives 'C:\Windows\system32\drivers\etc\hosts'
  4. // on Linux gives 'C:/Windows/system32/drivers/etc/hosts'
« Last Edit: May 01, 2022, 05:50:49 pm by WayneSherman »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: String Type Helper Join
« Reply #1 on: May 01, 2022, 06:13:29 pm »
//none of these work correctly
AString.Join('\', ['Windows', 'System32']);  //this doesn't do anything
Your assertion is not correct.
It is just that your statement throws away the result of the function.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
Re: String Type Helper Join
« Reply #2 on: May 01, 2022, 06:17:15 pm »
Delphi has a TPath type, I think, for path strings.

Laprado

  • New member
  • *
  • Posts: 8
Re: String Type Helper Join
« Reply #3 on: May 02, 2022, 01:08:41 am »
To use join function:

AString := string.Join('\', ['c:', 'Windows', 'System32']);

For path you may use ConcatPaths from SysUtils unit:
APath := ConcatPaths(['c:', 'Windows', 'System32']);

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: String Type Helper Join
« Reply #4 on: May 02, 2022, 01:38:26 am »
Also, it would be nice to have a "PathJoin" helper which automatically uses the correct OS path separator and normalizes the path to remove double separators and fix wrong separators

You are using literal path separators! Instead, use the PathDelim constant.

dbannon

  • Hero Member
  • *****
  • Posts: 2778
    • tomboy-ng, a rewrite of the classic Tomboy
Re: String Type Helper Join
« Reply #5 on: May 02, 2022, 02:01:29 am »
I personally consider this far more readable, simple and easy to spot mistakes -

Code: Pascal  [Select][+][-]
  1. AString := PathDelim + 'system32' + PathDelim + 'drivers' + PathDelim + 'etc' + PathDelim + 'hosts';

It could be improved by using macro to define a shorter name for PathDelim but you get used to it as it is.

Davo
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

WayneSherman

  • Full Member
  • ***
  • Posts: 243
Re: String Type Helper Join
« Reply #6 on: May 02, 2022, 06:32:25 pm »
I don't understand the choice to use a class function when working on a string instance is an obvious use case.  For example, I find it misleading that this does not result in 'abcdef':
Code: Pascal  [Select][+][-]
  1. 'abc'.Join('', ['def']);

Likewise, this does not work as expected:
Code: Pascal  [Select][+][-]
  1.   TemplateDir := Application.Location.Join(PathDelim, ['templates']);




« Last Edit: May 02, 2022, 06:57:44 pm by WayneSherman »

dbannon

  • Hero Member
  • *****
  • Posts: 2778
    • tomboy-ng, a rewrite of the classic Tomboy
Re: String Type Helper Join
« Reply #7 on: May 03, 2022, 02:30:52 am »
Wayne, it does not work as you expect, that is not necessarily a bug.

Consider this -

Code: Pascal  [Select][+][-]
  1. var
  2.     LeftBit : string = 'left';
  3.     RightBit : string = 'right';
  4.     MyString : string = 'abc';
  5. begin
  6.     MyString := MyString.Join(PathDelim, [LeftBit, MyString, RightBit]);
  7.     // MyString is now 'left/abc/right'
  8.  


If Join automatically inserted its own value into the set, as you seem to expect, the code above would give a different result. But if that was the case, would you expect it to add it as the first item in the set, the last item in the set or the middle item (where I want it) ?

Davo
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: String Type Helper Join
« Reply #8 on: May 03, 2022, 03:24:43 am »
Perhaps reading the documentation would help to understand how it works rather than imagining how it should work.

WayneSherman

  • Full Member
  • ***
  • Posts: 243
Re: String Type Helper Join
« Reply #9 on: May 03, 2022, 06:38:19 am »
Wayne, it does not work as you expect, that is not necessarily a bug.

Yes, I agree it is not a bug.  I just find it not intuitive when Lazarus code completion recommends helpers that (in my opinion) should not be showing up on a string instance since those functions don't operate on it.

Quote
MyString := MyString.Join(PathDelim, [LeftBit, MyString, RightBit]);
    // MyString is now 'left/abc/right'
If Join automatically inserted its own value into the set, as you seem to expect, the code above would give a different result. But if that was the case, would you expect it to add it as the first item in the set, the last item in the set or the middle item (where I want it)

If MyString has a value when Join is called, I would expect it to be the first string (i.e. the left most string; typically a concatenate adds to the end of a string).  If it operated on string instances, to insert it into an arbitrary position you would have to:

Code: Pascal  [Select][+][-]
  1. MyString := ''.Join(PathDelim, [LeftBit, MyString, RightBit]);
  2. //EDIT: nope, that won't do it, I forgot we have a delimiter which
  3. //would end up at the start of the string. it would have to be like this:
  4. MyString := LeftBit.Join(PathDelim, [MyString, RightBit]);

For clarity and to avoid confusion, a convention is now needed such that the Join helper should never be called on a string instance, but always on the type directly:

Code: Pascal  [Select][+][-]
  1. MyString := String.Join(...);  //this convention is needed
  2. MyString := SomeString.Join(...);  //never write code like this
  3. MyString := 'a string literal'.Join(...);  //never write code like this
« Last Edit: May 03, 2022, 04:57:59 pm by WayneSherman »

Zvoni

  • Hero Member
  • *****
  • Posts: 2300
Re: String Type Helper Join
« Reply #10 on: May 03, 2022, 08:59:52 am »
To add a bit of spice (or call it personal preference):
What confused me the most is the fact, that a "Join" is usually done on an Array (which the Syntax actually implies! --> ...Join(Delim, [ArrMember1, ArrMember2....])
So IMO it would make more sense to have something like
Code: Pascal  [Select][+][-]
  1. MyString:=MyArray.Join(....)
But Typehelpers for Arrays is a different can of worms, never mind existing code would break
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: String Type Helper Join
« Reply #11 on: May 03, 2022, 09:35:35 am »
Wayne, it does not work as you expect, that is not necessarily a bug.

Yes, I agree it is not a bug.  I just find it not intuitive when Lazarus code completion recommends helpers that (in my opinion) should not be showing up on a string instance since those functions don't operate on it.

This is consistent with the remainder of the language: You can call ordinary class methods and static class functions on an instance as well, helper types make no exception here. It's up to the user to call them correctly.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: String Type Helper Join
« Reply #12 on: May 03, 2022, 10:36:01 am »
Yes, I agree it is not a bug.  I just find it not intuitive when Lazarus code completion recommends helpers that (in my opinion) should not be showing up on a string instance since those functions don't operate on it.

That's a Lazarus IDE issue and should be discussed (and improvements contributed) elsewhere. The only possible way that that would impact on FPC as a language and on the RTL/FCL would be if the Lazarus team requested that function source be annotated to allow the IDE to improve its completion suggestions.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: String Type Helper Join
« Reply #13 on: May 03, 2022, 01:29:28 pm »
Yes, I agree it is not a bug.  I just find it not intuitive when Lazarus code completion recommends helpers that (in my opinion) should not be showing up on a string instance since those functions don't operate on it.

That's a Lazarus IDE issue and should be discussed (and improvements contributed) elsewhere. The only possible way that that would impact on FPC as a language and on the RTL/FCL would be if the Lazarus team requested that function source be annotated to allow the IDE to improve its completion suggestions.

Nothing needs to be annotated there, because the method is marked as class. Maybe Lazarus then needs to improve its completion display, because one can't easily differentiate between a class and an instance method. However calling a class method on an instance is valid code and thus the suggestion of that function by itself is valid as well.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: String Type Helper Join
« Reply #14 on: May 03, 2022, 02:21:08 pm »
Nothing needs to be annotated there, because the method is marked as class. Maybe Lazarus then needs to improve its completion display, because one can't easily differentiate between a class and an instance method. However calling a class method on an instance is valid code and thus the suggestion of that function by itself is valid as well.

Agreed. I was pointing out the one potential situation which might conceivably make this an FPC issue: as things stand it's not.

And even if it were booted back to the FPC project, I'd expect it to be in the form of a patch asking that %directives be added to the RTC or FCL, i.e. it would be here purely because source needed annotating rather than because anybody was asking that FPC's behaviour or Object Pascal's syntax be changed.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018