Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data::Dumper 2.101 and qr// #800

Closed
p5pRT opened this issue Nov 1, 1999 · 21 comments
Closed

Data::Dumper 2.101 and qr// #800

p5pRT opened this issue Nov 1, 1999 · 21 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 1, 1999

Migrated from rt.perl.org#1727 (status was 'resolved')

Searchable as RT1727$

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From michael@shoebox.net

Data​::Dumper 2.101 has a problem with qr// objects, in that it dies when it
encounters them during a dump. From glancing at 5.00562 I noticed this
appears to be fixed, but needing this fixed now, and not having (or really
wanting) a devel Perl in production, I decided to patch it. Below is the
patch I've made, in case it's useful to anyone else.

The patch is a little ugly, mostly due to the fact that qr// objects are odd
beasts when compared to everything else (no id to track in the seen hash,
the stringified version can look like just about -anything-, etc.).

Michael

=== patch ===

Inline Patch
diff -u Data-Dumper-2.101-orig/Dumper.pm Data-Dumper-2.101/Dumper.pm
--- Data-Dumper-2.101-orig/Dumper.pm	Fri Apr 30 17:29:35 1999
+++ Data-Dumper-2.101/Dumper.pm	Sun Oct 31 17:42:26 1999
@@ -221,7 +221,15 @@
 
     ($realpack, $realtype, $id) =
       (overload::StrVal($val) =~ /^(?:(.*)\=)?([^=]*)\(([^\(]*)\)$/);
-    
+
+    if ($type eq 'Regexp' && $val =~ /^\(?/) {
+      # assume this is a qr// pre-compiled regex and short-circuit things
+      my $re = $val;
+      $re =~ s/'/\\'/g;
+      return "qr'$re'";
+    }
+
+
     # if it has a name, we need to either look it up, or keep a tab
     # on it so we know when we hit it later
     if (defined($name) and length($name)) {
diff -u Data-Dumper-2.101-orig/Dumper.xs Data-Dumper-2.101/Dumper.xs
--- Data-Dumper-2.101-orig/Dumper.xs	Fri Apr 30 17:28:17 1999
+++ Data-Dumper-2.101/Dumper.xs	Mon Nov  1 15:18:00 1999
@@ -175,10 +175,49 @@
 	realtype = SvTYPE(ival);
         (void) sprintf(id, "0x%lx", (unsigned long)ival);
 	idlen = strlen(id);
-	if (SvOBJECT(ival))
+	if (SvOBJECT(ival)) {
 	    realpack = HvNAME(SvSTASH(ival));
-	else
+
+	    if (SvMAGICAL(ival)
+		    &&
+		strEQ(realpack, "Regexp")
+		    &&
+		mg_find(ival, 'r')
+	    ) {
+		char   *re_str;
+		char   *re_qstr;
+		I32	sq		=  0;	/* number of single quotes */
+		STRLEN	re_len		=  0;
+		STRLEN  re_qlen;
+		int	i;
+
+		re_str = SvPV(val, re_len);
+
+		for (i = 0; i < re_len; i++)
+			if (re_str[i] == '\'')	sq++;
+
+		New(0, re_qstr, re_len + sq + 1, char);
+
+		for (i = 0, re_qlen = 0; i < re_len; i++, re_qlen++) {
+			if (re_str[i] == '\'')
+				re_qstr[re_qlen++] = '\\';
+			re_qstr[re_qlen] = re_str[i];
+		}
+
+		re_qstr[re_qlen + 1] = '\0';
+
+		sv_setpv (retval, "qr'");
+		sv_catpvn(retval, re_qstr, re_qlen);
+		sv_catpv (retval, "'");
+
+		Safefree(re_qstr);
+
+		return 1;
+	    }
+
+	} else {
 	    realpack = Nullch;
+	}
 
 	/* if it has a name, we need to either look it up, or keep a tab
 	 * on it so we know when we hit it later
Perl Info


Site configuration information for perl 5.00503:

Configured by wolfm at Thu Sep 16 02:46:38 AKDT 1999.

Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration:
  Platform:
    osname=linux, osvers=2.0.36, archname=i386-linux
    uname='linux beowulf 2.0.36 #2 sun may 2 02:20:41 akdt 1999 i586 unknown '
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef useperlio=undef d_sfio=undef
  Compiler:
    cc='gcc', optimize='-O2', gccversion=2.7.2.3
    cppflags='-Dbool=char -DHAS_BOOL -I/usr/local/include'
    ccflags ='-Dbool=char -DHAS_BOOL -I/usr/local/include'
    stdchar='char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=4, ptrsize=4, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    alignbytes=4, usemymalloc=n, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lndbm -lgdbm -ldbm -ldb -ldl -lm -lc -lposix -lcrypt
    libc=, so=so, useshrplib=false, libperl=libperl.a
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl 5.00503:
    /home/michael/perl5lib/i386-linux
    /home/michael/perl5lib
    /home/michael/projects/shoebox.net/perl5lib
    /usr/lib/perl5/i386-linux/5.00503
    /usr/lib/perl5
    /usr/local/lib/site_perl/i386-linux
    /usr/local/lib/site_perl
    .


Environment for perl 5.00503:
    HOME=/home/michael
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/michael/bin:/usr/local/bin:/usr/bin:/usr/bin/X11:/bin:/usr/games:/usr/local/sbin:/usr/sbin:/sbin:.
    PERL5LIB=/home/michael/perl5lib:/home/michael/projects/shoebox.net/perl5lib
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From [Unknown Contact. See original ticket]

Michael Fowler writes​:

+ if ($type eq 'Regexp' && $val =~ /^\(?/) {

This matches always.

Ilya

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From @vanstyn

In <199911020158.UAA23217@​monk.mps.ohio-state.edu>, Ilya Zakharevich writes​:
:Michael Fowler writes​:
:> + if ($type eq 'Regexp' && $val =~ /^\(?/) {
:
:This matches always.

Note that with _62​:
  crypt% perl -MData​::Dumper -we 'print Dumper(bless{a=>1,b=>2},"Regexp")'
  $VAR1 = qr/Regexp=HASH(0x80f869c)/;
  crypt%

I think the above test gets it right in that case, at least.

Perhaps we need the concept of 'reserved packages', but at least things
like 'ARRAY' etc tend to be all uppercase; as things currently stand, I
would not generally expect a typical user of perl to know that she might
cause herself problems by naming a package 'Regexp'.

Even better would be, as discussed before, two new tests​: the package
an object is blessed into (or undef), and the underlying type of
variable (hashref, compiled re, etc). Conflation of these two by ref()
makes life difficult when you need to be able to separate them.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From [Unknown Contact. See original ticket]

Hugo writes​:

In <199911020158.UAA23217@​monk.mps.ohio-state.edu>, Ilya Zakharevich writes​:
:Michael Fowler writes​:
:> + if ($type eq 'Regexp' && $val =~ /^\(?/) {
:
:This matches always.

Note that with _62​:
crypt% perl -MData​::Dumper -we 'print Dumper(bless{a=>1,b=>2},"Regexp")'
$VAR1 = qr/Regexp=HASH(0x80f869c)/;
crypt%

I think the above test gets it right in that case, at least.

I repeat​: the =~ test as written is a NOOP.

Ilya

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From [Unknown Contact. See original ticket]

On Mon, Nov 01, 1999 at 08​:58​:00PM -0500, Ilya Zakharevich wrote​:

Michael Fowler writes​:

+ if ($type eq 'Regexp' && $val =~ /^\(?/) {

This matches always.

Oops, it should be​:

+ if ($type eq 'Regexp' && $val =~ /^\(\?/) {

A fixed version of the patch is at www.shoebox.net/perl/Data-Dumper-qr.patch.

Michael
--
There isn't a mome rath alive that can outgrabe me.
--

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From @vanstyn

In <199911020223.VAA23333@​monk.mps.ohio-state.edu>, Ilya Zakharevich writes​:
:Hugo writes​:
:>
:> In <199911020158.UAA23217@​monk.mps.ohio-state.edu>, Ilya Zakharevich writes​:
:> :Michael Fowler writes​:
:> :> + if ($type eq 'Regexp' && $val =~ /^\(?/) {
:> :
:> :This matches always.
:>
:> Note that with _62​:
:> crypt% perl -MData​::Dumper -we 'print Dumper(bless{a=>1,b=>2},"Regexp")'
:> $VAR1 = qr/Regexp=HASH(0x80f869c)/;
:> crypt%
:>
:> I think the above test gets it right in that case, at least.
:
:I repeat​: the =~ test as written is a NOOP.

Sorry, my mistake.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Nov 1, 1999

From @gsar

On Mon, 01 Nov 1999 15​:52​:55 -0900, Michael Fowler wrote​:

Data​::Dumper 2.101 has a problem with qr// objects, in that it dies when it
encounters them during a dump. From glancing at 5.00562 I noticed this
appears to be fixed, but needing this fixed now, and not having (or really
wanting) a devel Perl in production, I decided to patch it. Below is the
patch I've made, in case it's useful to anyone else.

The patch is a little ugly, mostly due to the fact that qr// objects are odd
beasts when compared to everything else (no id to track in the seen hash,
the stringified version can look like just about -anything-, etc.).

You need to fix overload.pm to get that right. See these for how it was
done in the development branch​:

  ftp​://ftp.linux.activestate.com/pub/staff/gsar/APC/5.005_58/diffs/3570.gz
  ftp​://ftp.linux.activestate.com/pub/staff/gsar/APC/5.005_62/diffs/4078.gz

Sarathy
gsar@​ActiveState.com

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 1999

From [Unknown Contact. See original ticket]

:The patch is a little ugly, mostly due to the fact that qr// objects are odd
:beasts when compared to everything else (no id to track in the seen hash,
:the stringified version can look like just about -anything-, etc.).

How does one recreate a qr// object at run-time from XS without constructing
a perl code string and eval'ing it?

I'm asking just in case someone wishes to have Storable handle that kind
of objects in the near future.

Raphael

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 1999

From [Unknown Contact. See original ticket]

Hi,

Raphael Manfredi​:

How does one recreate a qr// object at run-time from XS without constructing
a perl code string and eval'ing it?

Umm.. you don't?

I'm asking just in case someone wishes to have Storable handle that kind
of objects in the near future.

I'd _really_ like to see Storable do that, too.

My application is a bunch of processes which send messages to each other,
and specifying the filter with a Perl regex is way cool. ;-)

On a related note, Perl should simplify regexp flags.

$r=qr(abc);
$r=qr($r);
$r=qr($r);
p $r
results in
  (?-xism​:(?-xism​:(?-xism​:abc)))
(using 5.005_03). That's ugly, and it means that my regexp handlers need
to go through some lengths keeping the original string around so that the
thing doesn't eat more and more memory.

Then again, I could write a regexp to simplify the regexp. :-)

--
Matthias Urlichs | noris network GmbH | smurf@​noris.de | ICQ​: 20193661
The quote was selected randomly. Really. | http​://www.noris.de/~smurf/
--
It has long been known that one horse can run faster
than another -- but which one? Differences are crucial.
  --Lazarus Long

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 1999

From @gsar

On Tue, 02 Nov 1999 10​:46​:16 +0100, Raphael Manfredi wrote​:

​:The patch is a little ugly, mostly due to the fact that qr// objects are odd
​:beasts when compared to everything else (no id to track in the seen hash,
​:the stringified version can look like just about -anything-, etc.).

How does one recreate a qr// object at run-time from XS without constructing
a perl code string and eval'ing it?

I'm asking just in case someone wishes to have Storable handle that kind
of objects in the near future.

FWIW, I'm totally uncomfortable with the "design" of these Regexp
"objects". (See archives for prior vague mutterings and
disenchantment.)

These things are neither true Perl objects (in the sense that
an external module "owns" them and provides their implementation),
nor are they first class internal entities (such as ARRAY, HASH
and the rest are). They are stuck in a murky netherworld with a
bad name and hidden unconventional overload semantics.

I'd much rather than they were straight objects (owned by re​::?)
with overload stringify magic. That way, everyone knows what they
are and can deal with them in a regular way.

Sarathy
gsar@​ActiveState.com

@p5pRT
Copy link
Author

p5pRT commented Nov 2, 1999

From @TimToady

Gurusamy Sarathy writes​:
: I'd much rather than they were straight objects (owned by re​::?)
: with overload stringify magic. That way, everyone knows what they
: are and can deal with them in a regular way.

A number of other things should work that way too. Exceptions,
filehandles, and maybe version numbers. The trick, as always, is to
get the methods implemented without any startup overhead. Maybe we
could start using the CC backend to link standard methods into the
binary image somehow. We might need to have a midiperl in between
miniperl and perl for that, though. :-)

Larry

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

FWIW, I'm totally uncomfortable with the "design" of these Regexp
"objects". (See archives for prior vague mutterings and
disenchantment.)

These things are neither true Perl objects (in the sense that
an external module "owns" them and provides their implementation),
nor are they first class internal entities (such as ARRAY, HASH
and the rest are). They are stuck in a murky netherworld with a
bad name and hidden unconventional overload semantics.

I'd much rather than they were straight objects (owned by re​::?)
with overload stringify magic. That way, everyone knows what they
are and can deal with them in a regular way.

IIRC, it was done this way as a temporary measure. What was really
wanted is a way to attach the compiles RE to a scalar, but not
loose it when it is assigned to another.

If we can solve that, maybe with a special SV type or something, then
there is no need for the result of qr to be a reference.

Graham.

Sarathy
gsar@​ActiveState.com

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

Graham Barr wrote, in part​:

What was really
wanted is a way to attach the compiles RE to a scalar, but not
loose it when it is assigned to another.

Allowing 'use overload'ed objects to have an assignment overload
would be a good way to do both this and to make overloading
more useful in general.

There's a fairly amusing explanation of why '=' does not really
mean '=' in overload.pm's POD, but I can't tell if that's primarily
an ideological decision or if allowing overload of assigments would
be difficult to implement. I suspect the latter.

If we can solve that, maybe with a special SV type or something, then
there is no need for the result of qr to be a reference.

With overloads, it can be a reference blessed in to re​::. re​::
objects could be overloaded as required, prefereably with C
implementations of the overload subs.

Yes, that'd be slower than a special SV, but it would pave the way
toward a more general overloading mechanism so that a new special
SV type isn't needed for the next similar application that wanders
by.

And then any speedups applied to this mechanism might then improve
all overloading...

FWIW,

Barrie

P.S. That's amusing in a positive sense :-).

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From @gsar

On Wed, 10 Nov 1999 07​:40​:43 CST, "Graham Barr" wrote​:

FWIW, I'm totally uncomfortable with the "design" of these Regexp
"objects". (See archives for prior vague mutterings and
disenchantment.)

These things are neither true Perl objects (in the sense that
an external module "owns" them and provides their implementation),
nor are they first class internal entities (such as ARRAY, HASH
and the rest are). They are stuck in a murky netherworld with a
bad name and hidden unconventional overload semantics.

I'd much rather than they were straight objects (owned by re​::?)
with overload stringify magic. That way, everyone knows what they
are and can deal with them in a regular way.

IIRC, it was done this way as a temporary measure. What was really
wanted is a way to attach the compiles RE to a scalar, but not
loose it when it is assigned to another.

If we can solve that, maybe with a special SV type or something, then
there is no need for the result of qr to be a reference.

I have no problem with it being a blessed reference. My issues are
only with the fact that the perl-level "typing" is not regular like
you'd expect from dealing with other objects​:

* there's no namespace called "Regexp" anywhere that provides the
  implementation.

* the stringify overload is totally invisible and behind-the-scenes.

This leads to very surprising behavior because ref() says one thing
and stringification disagrees even after a C<no overload '""'>.

Sarathy
gsar@​ActiveState.com

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From @TimToady

Barrie Slaymaker writes​:
: With overloads, it can be a reference blessed in to re​::. re​::
: objects could be overloaded as required, prefereably with C
: implementations of the overload subs.
:
: Yes, that'd be slower than a special SV, but it would pave the way
: toward a more general overloading mechanism so that a new special
: SV type isn't needed for the next similar application that wanders
: by.
:
: And then any speedups applied to this mechanism might then improve
: all overloading...

I don't know about assignment overloading, but I'd agree that we need
to make objects faster, not SVs slower. And that a number of internal
beasties that aren't currently objects could be objectified. Certainly
we're moving that direction with exceptions.

And as Sarathy just pointed out, we need to make these internal objects
behave like "real" objects as much as possible, except for sloth.

I think the definition of an internal object is something like
"implemented entirely in C code." Whether the definition should also
exclude XSUB implementation is something that is not clear to me yet.
Internal objects just need to be "there" when Perl starts, and not have
to go through a long bootstrap process. Perhaps we can do some
optimizations based on the notion that internal objects may be derived
from but are never derived themselves. There's some affinity to class
UNIVERSAL here that I can't quite put my finger on this early in my life.

Larry

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

Larry Wall wrote, in part​:

I don't know about assignment overloading

Me either :-). Overloaded designs are tricky enough to begin
with.

Without being able to overload assignment, you can build an
object that drives completely like a scalar with one subtle
yet frequently encountered exception​: assignment is shallow.

There are more assignments done in most stretches of Perl than
any other "mathematical" operator. Yet here it's the odd man
out.

Having it be shallow is a hard gotcha for people to remember,
especially if we're actively using other overloaded ops for
an object.

If it feels like a scalar most of the time you're using it, it's
just too easy to forget the gotcha when typing '=' instead of
'+=' or '.=', for example.

I do know the tie workaround, and it's an awkward departure
from normal Perl, IMO.

I'm not advocating heavy use of operator overloading here, but
when you really want it, it'd be nicer and safer if it was a more
complete API. And I'm not criticizing the design of overload.pm
either. I like having it​: it's been useful to me on several
occasions. I'm greedy, though​: I want completeness :-).

I suspect that it's hard to do or it would have been implemented
already, though. And not that I have tuits or expertise to
put my money where my mouth is :-/.

- Barrie

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

Barrie Slaymaker writes​:

With overloads, it can be a reference blessed in to re​::. re​::
objects could be overloaded as required, prefereably with C
implementations of the overload subs.

Yes, that'd be slower than a special SV, but it would pave the way
toward a more general overloading mechanism so that a new special

Being slower will not pay anything. But my deliberations braught me
this way​: suppose we "pretend" that RExen are references to objects
blessed into 'Regexp' with an overloaded stringification. "Pretend"
in the sense that we set up all the brouhaha in %Regexp​:: correctly.

But we leave the special case for stringification of a REx in sv.c.
Nobody can tell that actual call to Regexp->stringify is not
performed, that it is shortcircuted in sv.c. The current speed is
preserved, but RExen start to *look* like well-behaving citizens.

Ilya

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

Gurusamy Sarathy writes​:

This leads to very surprising behavior because ref() says one thing
and stringification disagrees even after a C<no overload '""'>.

Hmm? Are not you confused about the scope and semantic of no overload
'""'?

Ilya

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

Barrie Slaymaker <barries@​slaysys.com> writes​:
|| Larry Wall wrote, in part​:
|| >
|| > I don't know about assignment overloading
||
|| Me either :-). Overloaded designs are tricky enough to begin
|| with.
||
|| Without being able to overload assignment, you can build an
|| object that drives completely like a scalar with one subtle
|| yet frequently encountered exception​: assignment is shallow.

But what is the meaning of overloaded assignment? In
particular, how do you distinguish between assigning a
new value to an object of a particular type from assigning
a typed value to a variable (thereby changing the type of
the variable)? When you write​:

  my $x = 1; # $x has an integer value
  $x = 'abc'; # now it has a string value

you don't expect the second assignment to be affected by the
previous contents of $x. The old contents are simply replaced
with the new contents *and its type*.

Overloading assignment only makes sense in a strongly typed
language. It might be possible to enforce it for "my Dog $x"
perhaps, but when the target is not strongly typed, it would
require a separate operator, distinct from =, for it to be an
overloaded assignment that preserved the type of the target
and did any massaging necessary of the newly assigned value
to make it conform to that type.

While writing the book, I hit upon a trick to do a type-specific
assignment for one particular case. I wanted a subroutine to
work when its argument might be an int or a BigInt or an
SSLeay​::bn. I needed to initialize a variable to 1, but for it
to be the same type as the argument, not an int. The trick for
that was​:

  my $product = $arg - $arg + 1; # 1, but int/BigInt/etc​: same as $arg

--
John Macdonald jmm@​jmm.pickering.elegant.com

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

On Wed, Nov 10, 1999 at 09​:30​:51PM -0500, John Macdonald wrote​:

|| Without being able to overload assignment, you can build an
|| object that drives completely like a scalar with one subtle
|| yet frequently encountered exception​: assignment is shallow.

But what is the meaning of overloaded assignment? In
particular, how do you distinguish between assigning a
new value to an object of a particular type from assigning
a typed value to a variable (thereby changing the type of
the variable)? When you write​:

my $x = 1;        \# $x has an integer value
$x = 'abc';       \# now it has a string value

you don't expect the second assignment to be affected by the
previous contents of $x. The old contents are simply replaced
with the new contents *and its type*.

Overloading assignment only makes sense in a strongly typed
language.

Which Perl became now (at least enough to make overloading assignment
easy). See `PREPARE' thread.

Ilya

@p5pRT
Copy link
Author

p5pRT commented Nov 10, 1999

From [Unknown Contact. See original ticket]

John Macdonald wrote​:

When you write​:

my $x = 1;        \# $x has an integer value
$x = 'abc';       \# now it has a string value

you don't expect the second assignment to be affected by the
previous contents of $x. The old contents are simply replaced
with the new contents *and its type*.

And that's a clear statement of the problem. It all hinges on
the meaning of 'contents'​: are the contents of a reference the
reference or the referred-to value? Perl considers it to be
the reference itself. What I'm asking for is to have the option
to completely emulate scalars and be able to define scalar-like
objects for which the contents are the referred-to value. The
option of extending weak typing to be able to include some blessed
references.

It would allow people to make simple-as-a-scalar APIs.

Consider​:

  my $x = 1 ;
  my $y = Math​::BigInt->new( 10 ) ;

  ... much code passes ...

  $y += 1 ;
  $x = $y ;

${x}'s old contents are _not_ replaced by ${y}'s contents ('11'),
but the type has been replaced. Do a

  $y->internal( 2 ) ; ## not a public API, but you get my point

some time later, in a module far, far away, and the value of $x
gets whammied at a distance. Which can be a subtle problem if
you're not expecting it.

What I'm proposing is an overloaded assignment operator
appropriate for a weakly typed language.

In my simple way, I'm thinking of something like​:

---------8<------------
package MyInt ;

use overload "assign" => \&assign ;

...

sub assign {
  ## Call copy ctor
  return shift->new() ;
}

---------8<------------

So​:

  my $a = MyInt->new( 6 ) ;

  my $b = $a ; ## calls MyInt​::assign( $a )
  $a = 5 ; ## sets $a to be a scalar containing the integer 5

  print "$a $b\n" ;

would yield the least surprising (IMO) output "5 6\n" and leave $a
a scalar and $b a MyInt.

That's necessarily as powerful a metaphor as you get when the type
of the target is immutable, as it is in strongly typed languages.
But it's exactly this approach that's made Perl so nice​: ints,
floats, strings, and CORE​::God knows only what else work that way.
It's DWIM.

If you want something more like a strongly typed language, then
this next bit could be used to implement

- weak typing,

- 'clingy' typing, which allows the target to try to
  preserve it's type, but also allows it to revert
  back if it can't, or

- a poor man's strong typing, only checked at run time and
  with none of the nice optimizations possible under real strong
  typing,

all at the author's discretion.

---------8<------------
package MyInt ;

use overload "assign" => \&assign ;

use Carp ;
use UNIVERSAL qw( isa ) ;

## Set $mode to 'weak', 'clingy', or 'strong'
my $mode = 'clingy' ;

...

sub assign {
  my ( $dest, $source ) = @​_ ;
  if ( isa( $dest, "MyInt" ) ) {
  if ( $mode ne 'weak' && $source =~ /^\d*$/ ) {
  ## Preserve the destination's type
  return $dest->set_to( $source ) ;
  }
  else {
  carp "Can't assign $source to a MyInt"
  if $mode eq 'strong' ;
  cluck "watch out​: assignment throwing away MyInt status"
  if $^W ;
  return $source ;
  }
  }
  else {
  ## We're assigning to a scalar, there is no meaningful
  ## thing in $dest, but I suppose you could want to know
  ## the value $dest for debugging purposes. Here, I don't
  ## care.
  ##
  ## Call copy ctor
  return $source->new() ;
  }
}

## Assume similar code in package MyOtherInt.

---------8<------------

Then​:

  my $a = MyInt->new( 6 ) ;
  my $b = MyOtherInt->new( 7 ) ;

  $b = $a ; ## calls MyOtherInt​::assign( $b, $a )
  $a = 5 ; ## calls MyInt​::assign( $a, 5 )

  print "$a $b\n" ;

Would output "5 6\n" and leave the types of $a and $b alone.
Overloading collisions would be resolved by calling the target's
overload, as shown by the line "$b = $a ;".

It's late. I'm probably ignoring something here. Ignorance is
bliss :-). I'm not sure whether weak, clingy or strong typing is least
surprising. I suspect that it would be application and programmer
dependant. Weak would be least surprising in most cases, probably,
and simplest to explain. The so-called "strong" typing shown here
is not a good idea given my Dog $spot ; it would lead to metaphor
confusion.

And this all may be a bit much, especially if assignment overloading's
tough or expensive to implement. But to be able to extend the range
of types that behave like scalars would be nice.

- Barrie

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant