Perl is worse!

Steve Lamb grey at despair.rpglink.com
Thu Jul 27 18:28:25 EDT 2000


On 27 Jul 2000 20:24:38 GMT, Martijn Faassen <m.faassen at vet.uu.nl> wrote:
>In the end if you want to add your data together, you need to know what
>the result will be. If you want to substract your data, you also need
>to know. 

    That all depends.  In python, yes, you need to know.  Why?  Because 1 +
"foo" doesn't work.  Sure, in perl you get 1, but you don't get blown out of
the water because of it.  OTOH, in Perl, if you meant to do a string addition
there is a different.syntax.for.that.  Because of this you know that "foo"
doesn't equal anything, IE, 0.

>What if your data is "foo" and you add them together? What if
>the user gave some input and you don't *know* what the user entered?

    Then that would be a user error, wouldn't it?  You can check for those
things.  If you're relying upon user input you don't need type checking to do
it.  

python:
try:
  b = b + 1
except TypeError:
  print "Numbers, stupid, not letters."

perl:
unless (int($a)){
  print("Numbers, stupid, not letters.\n")
}
$a++

    The difference comes when you do something like this:

(/^(\d{1,2})[Dd](\d{1,3})$/ || /^(\d{1,2})[Dd](\d{1,3})([\+\-])(\d{1,2})$/) 

    Perl or Python, doesn't matter, you should be able to read it.  Simple
regular expression to take die codes from RPGs (3D6+3, for example) and break
it down into the component parts regardless of their being a modifier to the
actual dice rolled.  What does this sample show?  Same thing that the previous
one did.

(/^(\d{1,2})[Dd](\d{1,3})$/ || /^(\d{1,2})[Dd](\d{1,3})([\+\-])(\d{1,2})$/) 
     $1             $2               $1           $2       $3      $4

    I already /know/ that the user supplied data are numbers!  The regular
expression has taken care of that for me.  That, right there, is my checking.  
You pass fooDfoo+foo through that filter then we'll have something to talk
about.  I don't need range telling me that I'm supplying an invalid data type
because, unless the re module is seriously broken, it isn't going to happen. 
To think that the only way to catch such errors is at the same level, when
something is called, is absurd.  Especially, as I said, when we are taking the
data type from context!  

    I mean, I know those are numbers, the regex prohibits numbers in 1,2 and
4.  I know 3 is going to be + or -.  That is all it can be.  But because regex
is considered a string operation it assumes that all returns are strings.
Because of this any assignments you make from those returns are going to be
strings unless you force them into another type.  This even though I not once
told it what type the data is!  If it is giving a type from the first
operation performed on that variable then why can it not also change types
based on subsequent operations?  

>I think in your case you usually need to remember what type your data
>is *anyway*, and what's worse you need to know what will happen to your
>data for various cases:

    Assumption: that data checking cannot be performed by the programmer.  

    False assumption, I've given two examples where the data will be what I
want because I have made the appropriate checks.  One comes right from the
program that I am porting to Python to learn Python.  In fact, that program
relies on user input every step of the way yet I've not had any problems
performing the operations I want to perform on the data.

>This may become quite unobvious in various cases, and may happen by
>accident, right?

    Doesn't mean the programming language should barf on it.  I am of the
opinion that a /lot/ more operations are performed where a lack of type
checking is a virtue than a bane.  I really dislike having to explicitely
declare data as a certain type just for an operation, especially after having
programmed in a language where such is not required and especially if I have
control of the dataflow throughout the entire course of its life.  Not only
does this cause problems for simple operations like extracting numbers with
regex to be manipulated with mathematics, but also internal data structures
where the author is defining things on the fly and needs to perform both
string and numerical operations on, say, the keys of a hash/directory.

>Though I understand the case for genericity, I don't really see it here.

    I see it the other way.  Though I understand the case for typing, I rarely
see a case where it is actually useful and, in fact, many cases where it is a
bane.  I'd much rather have to deal with the few cases when they arise than
the many cases when they arise.  For example, mathematics which require
roll-over at a certain number (unsigned int, for example).  This is more so in
a language which does have certain cases when types can change (int versus
float, for example) and the initial type is implicitly stated but requires an
explicit declaration to change that implicit type.  

    Either have all types be immutable regardless of context unless explicitly
stated or have all types mutable as best as possible based on context with the
option of explicit typing.  The half-and-half is just as confusing as a lot of
what a lot of Python pundants dislike about Perl.  Just like lists and
directories (does that include tuples?  I forget) being referenced but the
"single" data types (integer, character, I believe string, not sure) being
copied.  That is no less magical and confusing than, say, using an implicit $_
in a foreach loop or constructing a data loop from @lines into %lines using
$line to do it.  $lines{$line} = $line[$line] is always fun to bedazzle
newbies, isn't it?  No different than implicit typing, IMHO, except here I do
have cues as to what is a scalar, a hash and an array.

>But what if that makes no sense? What if I entered 'foo' in the config
>file where I needed to enter a number? Won't you get a weird bug now?

    OK, go ahead and do it in Python, what do you get?  An exception.

    Do it in Perl, what do you get?  The /possibility/ of odd behavior.

    The language doesn't know!  /I/ am the human.  /I/ am the smart one.  I
don't need a language to tell me that adding numbermatch.group(1) and
numbermatch.group(2) is invalid when they came from (\d*) constructs in a
regular expression.  They're numbers!  I made sure they are numbers!  Right
there, \d.

    And that is the whole point.  In both cases you have to do error checking.
The difference is that with the implicit types enforced it gets in the way.
I'd much rather the language assume I am smart enough do to my own checking
and assured that the data is valid than to assume I'm too stupid to do it and
crap the program out when something doesn't match what it /thinks/ is invalid
even though I have taken pains to ensure it is.

>This script won't do anything.

    Thank you for so stating the obvious, especially when I provided the
interactive mode right after it.

>I imagine the reason Python doesn't complain here is that it can treat
>expressions as statements, and that sometimes this makes sense, such
>as when there's a function call:

    The problem is, outside the context of interactive mode what good does it
do?  Nothing that I can think if.  Have you made calls for Python to check for
such things just as it checks implicit types?  If not, why not?  In both cases
the assumption is that the programmer does dumb things and should be babysat.

>I'm not claiming we want to be strict about things at all times. If
>I thought that I wouldn't be using Python. I was claiming that 'guessing'
>what a line of code is supposed to mean can be bad. I mean, really:

>"foo1" + 1 # 1
>"1foo" + 1 # 2
>"1" + 1 # 2
>" 1" + 1 # 2
>"\n1" + 1 # 2
>"1*2" + 1 # 2

>Are you sure this never gives you any odd output?

    Positive.  Because you have made the base assumption that the only way to
check data is for the language to do it instead of the programmer.  I know
what data I am passing, I don't need type checking in an implicit system to
provide annoyances all over the place for the off chance that I /might/ goof
up.  Quite a Libertarian view, innit?  In a sentence.

    LET ME MAKE MISTAKES!

>No, giving up in the face of ambiguity versus guessing. Ambiguity tends
>to arise when I'm doing something wrong; if I did it right it wouldn't
>be ambiguous code. Besides, I wouldn't want to read such code even
>if it did the right thing; confusing.

    What ambiguity?  Data is data.  I don't find it confusing when you unlearn
the concept of types.  I mean, how many people out there who program in other
languages consider Python confusing because whitespace is used for block
declaration instead of {} or BEGIN/END or whatever other block declaration is
out there.  

    If your mind can wrap itself around the concept of a lack of braces for
block declaration then there should be no problem unlearning the concept of
data "types".  

>In Python there are tons of ways to do it too. :)

    So long as you tell it explicitly what you want even though its ambuigity
on the implicit typing is what cause the problem in the first place?  I'm
sorry, but I do not consider data confusing unless it is typed.  I see 1 and I
am confused why I can't add it to 2.  I don't /care/ if it is a char, string,
integer or floating.  It is 1 to me.

>Because I wasn't arguing for 'strict checking'; I was arguing not checking
>until the *last moment*, and if that makes no sense, give up.
>(unless you catch the exception, of course)

    Which makes no sense without declarations up front since you are allowing
ambiguity, to use your term, from the onset.

    Python: You need to know what data type it spews out for each operation.

    Perl: You need to know what the data contains.

    Either way, you got ambiguity.  

    As for catching the exception I'd much rather check the data first, thank
you.

>Not in OO code:

    Funny, we have implicit typing in OO code that causes problems later in
the code.  So yes in OO code.
   
>That works, as the check at the last moment could figure it out; there was
>such a method, so it executes it. Now if 'doit()' was absent and the system
>started guessing, we'd be in trouble, right?

    This is not, however, data.  Methods are functions, if there is nothing to
call, there is nothing to call.  1 is data, be it integer, float, char, string
or any other name you want to give it.

>So I don't need to know about what happens when I do "1foo" + 1?
>Or "foo1" + 1? Or "foo1" - 1? Presumably I'd need to check my user
>input *anyway*, right?

    Yup, that is exactly what you should be doing and if you were doing it
properly then you'd not have to rely upon the language to do it for you.  

    As I said, you're trading knowing what a certaion operation does with
certain data versus having to know what type of data a certaion operation
spits out at you.  

    6, half dozen.  Ring a bell?

>> Not that hard to remember.  Much easier, in fact, that having to
>> remember to declare everything from the onset or declare it each time you
>> need to use it in a particular context much less having to put in checks
>> in case you're trying to declare something into something which it cannot
>> be morphed into.

>But in Python you don't need to declare at all. You just need to explicitly
>say sometimes you want something changed into something else. If you
>want an integer, change your string into an integer. Do it early on if
>you don't want to do it everywhere and work with integers from then on.

    Thank you for ignoring what I said.  First off, in Perl I don't have to
declare at all as a rule and only need to worry about the exceptions.  In
Python it is the reverse, I need to declare as a rule except for the
exceptions.  Furthermore if I need to change my string into an integer I need
first check to make sure it is a string /THEN/ I can convert it to an integer.

>>> int(None)
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  TypeError: object can't be converted to int

{grey at teleute:~} perl
print int(null)."\n"

    This causes problems when using a regex that has an or that can match
different numbers of groups based on which or hits because any conversions on
any group that didn't hit now needs to be encapsulated in either a
try/except|finally block or an if.  You might like littering your code with
try/except and ifs which are only needed because the type checking isn't
allowing you to do things you should be able to do but personally I don't.  I
find it foolish that I need to check a variable to make sure it exists so I
can type it to integer when I know an integer is going into it in the first
place!  In short a regex which returns a number turns into...


$modifider = $4;

    ...has become...

if diematch.group(4):
  modifier = diematch.group(4)

    ...or...

try:
  modifier = int(diematch.group(4))
except TypeError:
  pass

    All because I don't want to have to int() the darn thing every time I use
it elsewhere.  That may seem like a small thing but in my mind, since I
consider everything just data, I move between string and numerical operations
seamlessly because data is /both/.

>The funny thing is that in Python this happens, and I'd agree with you,
>but it tends to happen more often for class instances

    Except I don't consider instances data.  They are structure or commands,
not data.

>We aren't so far apart in that sense; we just disagree about how many
>operations the basic datatypes should support. I personally never had
>trouble with having to call int() excessively, for instance. If you
>find you're doing that a lot in your code, something may be odd about the
>design of your code.

    I seriously doubt that.  All I'm doing is a basic regex match and
assignment of the matched data.  I haven't gotten into making complex data
structures yet in Python but I have a feeling the typing will get in the way
since a lot of the times that I manipulate keys in a hash/directory I move in
and out of numerical and string processing to get the job done.

>Note also that in your case, the only thing you're complaining about is
>that Python treats numbers and strings differently; Python doesn't care much
>whether your number is an integer or a float or a long integer, for instance.
>It doesn't distinguish between characters and strings either. The only
>addition to your type pantheon would seem to be the string/number
>dichotomy and the list/tuple dichotomy, nothing else. :)

    Hmmm, but you forget, lists, tuples and hashes are not data, they are
structure.  Hashes and arrays are not data, they are structure.  Classes that
hold only data are not data, they are structure.  Classes, in fact, to me, are
just structures that hold either functions (renamed to methods) or data.

    You have different types of data.  I have, conceptually, data, commands
and structure.  What /form/ those take and what semantics assigned to them
vary from language to language but the concepts to me are quite clear.

data = the information.
commands = the operations tha manipulate the data
structure = orgainzation of either data or, in the case of OO, commands as
well.

    1 is data.  Not integer, not string, not any other type that any other
language has cast upon it to help it out.  It is data.  That is how my mind
works and, in fact, that is how the minds of nearly every human being works.
1 is data.  What to do with that data depends on context.  There is no
"conversion" as that is purely a machine concept since to it, everything is
either on or off.  The difference between your position and mind is that
you're closer to the machine where the machine is closer to me.

    Lists, arrays, hashed, directories, classes, structs, etc, etc, etc are
all organizational in nature.  OO has the distinction of having the ability to
apply those organizing constructs to commands and not just data.

    Operations, functions, prodecures, methods.  All manipulate the data.  The
do something.  In OO they can be organized.

-- 
         Steve C. Lamb         | I'm your priest, I'm your shrink, I'm your
         ICQ: 5107343          | main connection to the switchboard of souls.
-------------------------------+---------------------------------------------



More information about the Python-list mailing list