in reply to Are strings lists of characters?

I had to think very long and hard for a case where having strings be character arrays would offer syntatically superior, more concise ways of expressing than using substr. I have finally come up with something. Consider this:

my @string = "hubris" =~ /(.)/sg; @string[0,2,5] = "etv" = ~ /(.)/sg; print reverse @string; __END__ virtue
This would be very awkward to achieve with substrs, particularly for more complex examples. (Bioinformatics might be an area where such could be useful.) But thanks to /(.)/sg expressiveness doesn't suffer much even here; the only concern I see is efficiency, if you do this a lot. But if that really is a probably, use a class with a real array in its guts and an overloaded stringification operator would probably suffice. And that one is downright trivial, something like: sub stringify { local $"; "@{$_[0]}" }

Assignment needs to be overloaded too, I guess, and would be slightly less trivial.

All in all, I conclude that there's not much need for such a feature at the language level. A module should suffice.

Makeshifts last the longest.

Replies are listed 'Best First'.
Re: Re: Are strings lists of characters?
by gjb (Vicar) on Oct 21, 2002 at 16:00 UTC

    A few quite common tasks map more naturally to a string-as-array approach. As an example, consider determining the common prefix (or suffix) of two strings.

    It can be done by regex matching:

    my @str = ('ABCD', 'ABEF'); my $str = join('-', @str); if ($str =~ /^([A-Z]+)[A-Z]*\-\1[A-Z]*$/) { print "common: '$1'\n"; } else { print "no match\n"; }
    but it's much more natural to do it with a simple for over the characters. Of course one can get around with substr, but it looks decidedly weird.

    Regards, -gjb-

      Way too hackish, not to mention it breaks if the chosen delimiter appears in your input strings - I'll get back to that in a bit though.

      To find the common prefix, you have to iterate over two variables; be that scalars or arrays. Using a for loop:

      my (@str1, @str2); my ($i, @prefix) = (0); for(@str1) { last if $_ ne $str2[$i++]; push @prefix, $_; }
      Or a while loop:
      my (@str1, @str2); my ($i, @prefix) = (0); push @prefix, $str1[$i++] while($str1[$i] eq $str2[$i]);
      I'd definitely prefer the while version, simply because the arrays are treated equally. Now let's look at how you'd do that over scalars:
      my ($s1, $s2) = ("ABCD", "ABEF"); my $i = 0; $i++ while substr($s1, $i, 1) eq substr($s2, $i, 1); my $prefix = substr $s1, 0, $i;

      That's hardly any different to read, way clearer than the regex solution, shorter and more idiomatic to boot, and doesn't break regardless of input. Ok, using the ternary operator for your code would shorten the regex approach, but if anything, it would probably conceil the code's intent even further.

      No, the only advantage strings-as-arrays would offer as far as I can see is for simulatenously replacing multiple non-contiguous parts of the string with parts of some other string. But then, that's such a rare circumstance that it shouldn't be unacceptably painful to just listify the strings using /(.)/sg for that, then glue the result back together.

      I do see compelling reasons to syntactically extend push, shift and friends for dealing with strings (although I also see reasons not to), but definitely not for making strings fullblown arrays.

      Makeshifts last the longest.