Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^4: Regex result being defined when it shouldn't be(?)

by chenhonkhonk (Acolyte)
on Nov 14, 2017 at 17:01 UTC ( [id://1203405]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Regex result being defined when it shouldn't be(?)
in thread Regex result being defined when it shouldn't be(?)

In C and in Perl, the result of a true conditional is 1. EDIT: In Perl, false can be 0 or "" depending on context. Or not. I don't like this. /edit

When I'm doing checks on a bunch of values, if I used the implicit return from a is_defined() function, I can only have a boolean in response. If I want multiple types of responses I must use an explicit equals. Even in the boolean context, nearly all my conditions have some sort of equality test - even in the case of less than or greater than. To not have that form is an exception when reviewing the code, I have to stop and say "wait, what is the function supposed to be returning? a number? a string? a reference/pointer?".

You even state that saying is_five()==1 is somehow not intuitive, when that is literally what your is doing, it is checking the truthfulness of whether that number is five.
  • Comment on Re^4: Regex result being defined when it shouldn't be(?)

Replies are listed 'Best First'.
Re^5: Regex result being defined when it shouldn't be(?)
by haukex (Archbishop) on Nov 14, 2017 at 17:50 UTC

    Just a couple of thoughts to try to get you into a Perl mindset :-)

    First, note that there is a conceptual gray area between what is "a function" and "an operator". In C, I could replace all a==b's with a function is_equals(a,b), and in Perl, often functions that accept a single argument are called "operators", see e.g. Named Unary Operators (Update: and Terms and List Operators (Leftward)). That's why I look at "return values" the same, no matter if it's a return value from an operator, or a return value from a function.

    In C and in Perl, the result of a true conditional is 1.

    Not quite, in Perl it could also be "0 but true" (e.g. sysseek), or in theory any other "true" value.

    In Perl, false can be 0 or "" depending on context. Or not. I don't like this.

    Look at it this way: If in C some function that returns an int is documented to return "a true value" on success, then that does not mean it will return 1 on success, it will return a nonzero value. Just in Perl, the same abstraction also applies if a function is documented to return "a false value".

    You even state that saying is_five()==1 is somehow not intuitive

    Do you think that instead of if ( a==5 ), I should write if ( (a==5)==1 )? But then I have to write if ( ((a==5)==1)==1 ), and if ( (((a==5)==1)==1)==1 ), and ... ;-)

    Plus, if a function is documented to return "a negative integer" on failure, like many C functions, you don't check that with somefunc()==-1 either.

    I have to stop and say "wait, what is the function supposed to be returning? a number? a string? a reference/pointer?"

    That's what the documentation is for... but if you wanted to be explicit in Perl, you could use if ( !(...) ) and if ( !!(...) ) (although the latter is of course redundant) - just don't use eq or == to check boolean values.

      Sysseek does not return a conditional, it returns a position or undef. I used the word conditional because it has a standard definition, and you are pretending to not understand it. Presumably. You can try to pretend being explicit about what a return value of something must be is bad, but if you say that you can't sit there and argue that having literally no idea is more informed. That is worse than wrong.

      In C there are more than one return values on failures, and there are functions which return status values or pointers. Ironically, mentioning sysseek is important, they couldn't do if( ! sysseek() ){...} because the failure state, undef, and a success state, 0, both become a truthful value after not so they ended up using an exception to get around a lousy logic style. Additionally, even if you use defined, you have to know in advance whether or not your function can return a defined-but-false value. With explicit return values, there is no confusion unless you are deliberately being foolish. Defined itself not returning the value on success or undef on not defined is probably the core reason we can't have sensible returns.

      And documentation is nice, except if you've ever worked in a production environment with code more than five minutes old. Say 20+ years.
        ... you are pretending to not understand it. Presumably. ... if you've ever worked in a production environment with code more than five minutes old. Say 20+ years.

        As I said, I was trying to present arguments for "the Perl way" of looking at things. I intended my replies to be friendly, and if you took offense at the few light jabs I made, I apologize. If, as you seem to be saying, you have 20+ years of C experience, then I know I could learn from that. I'm just offering my 20+ years of Perl experience here. As you can probably imagine I'm not a big fan of insults, and that's not what I'm trying to do here, but I am a fan of correctness, and unless I misunderstood you, I do think you're wrong in a couple of points.

        You can try to pretend being explicit about what a return value of something must be is bad, but if you say that you can't sit there and argue that having literally no idea is more informed. That is worse than wrong. ... With explicit return values, there is no confusion unless you are deliberately being foolish.

        Sorry but I think you are mistaken about what I said and meant. Let me be more direct: defined is documented to return "a Boolean value", nothing more. Testing a boolean with if( BOOL eq "" ) to check for false values is incorrect. As per Truth and Falsehood, which I linked to earlier, there are three basic "false" values in Perl: 0, "", and undef. The test would fail on the first case because "0" eq "" is false. (Update: More on the comparison operators here.)

        The way to explicitly check for "false" in Perl is if( not EXPR ) or the other variants I showed. The way to check for "true" is if( EXPR ), or, if you want to be really explicit about it, which was how I understood your argument, then use if( !!(EXPR) ) (see also "Bang bang" in perlsecret).

        Not quite, in Perl it could also be "0 but true" (e.g. sysseek), or in theory any other "true" value.
        Sysseek does not return a conditional, it returns a position or undef. ... Ironically, mentioning sysseek is important, they couldn't do if( ! sysseek() ){...} because the failure state, undef, and a success state, 0, both become a truthful value after not so they ended up using an exception to get around a lousy logic style.

        Are you talking about C or Perl here? Because in Perl, you can do if( !sysseek() ) to test for failure, that is the point of the "0 but true" return value - when evaluated as a number, it is 0, and in a boolean context, it is true. So the only false value sysseek should return is undef on failure, and it shouldn't normally throw an exception either. Note that the string "0 but true" is special-cased in Perl to not warn when it is used as a number, this is described in fcntl and ioctl. Another value that is sometimes used as a "numerically zero but true in a boolean context" value is the string "0E0".

        sysseek($fh,0,0) returned "0 but true" sysseek($fh,42,0) returned 42 sysseek($fh,-1,0) returned undef undef: bool=false, str= "", num=0 (warns: uninit x 2) "": bool=false, str= "", num=0 (warns: numeric) 0: bool=false, str= "0", num=0 "0": bool=false, str= "0", num=0 1: bool=true , str= "1", num=1 "1": bool=true , str= "1", num=1 "foo": bool=true , str= "foo", num=0 (warns: numeric) Perl's true: bool=true , str= "1", num=1 Perl's false: bool=false, str= "", num=0 "0 but true": bool=true , str="0 but true", num=0 "3 and true": bool=true , str="3 and true", num=3 (warns: numeric) "0E0": bool=true , str= "0E0", num=0 0E0: bool=false, str= "0", num=0 1E0: bool=true , str= "1", num=1 "1E0": bool=true , str= "1E0", num=1

        pryrt also wrote a good post in a similar vein here.

        Defined itself not returning the value on success or undef on not defined is probably the core reason we can't have sensible returns.

        Sorry, I don't understand this point.

        In C there are more than one return values on failures, and there are functions which return status values or pointers.

        Right, which is why I said "you don't check that with somefunc()==-1". What I meant is that if a function is documented to return a negative value on failure, I'd first use if( somefunc()<0 ), or, if I needed to inspect it closer, int rv = somefunc(); if ( rv<0 ) { handle_error(rv); } or something along those lines.

        Additionally, even if you use defined, you have to know in advance whether or not your function can return a defined-but-false value. ... And documentation is nice, except if you've ever worked in a production environment with code more than five minutes old.

        I completely agree that poorly maintained documentation is a problem. Fortunately, the Perl documentation for the most part doesn't suffer from that problem and can be taken seriously.

        Update 2019-08-17: Updated the link to "Truth and Falsehood".

        I'm wondering if, by focusing on the sysseek aside, you've missed the point about the return value of defined() itself. It returns something that is indistinguishable from the return value of the == operator. See below.

        By doing an explicit test against a single value, rather than leaving defined() to return a "truthy" value itself, future readers would be well within their rights to infer that defined() may return one of many integers (~4billion in 32bit world, ~18 billion billion in 64bit world, ...) or one of an infinitude of possible strings, and that compared value of 0 or "" is somehow magically important, without any indication that the importance comes because the function is returning a Boolean (or at least something that can be interpreted in a truthy manner). On the other hand, if you left !defined($var) as the sole element of the conditional, you would show you expect the return from defined() function to be truthy (Boolean), and are using it as such. To me, this is more clear than the comparison to the magic number (or magic string). But if you're the only person who will ever read your code, and you are 100% certain that perl will never change the false return to be 0|"0" instead of 0|"", then continue as you want. In which case, I'd recommend the defined($var)==0 rather than defined($var) eq '', because it seems more future proof, and programmers from other languages are possibly more accustomed to integers being mildly truthy (for example, c's if(5) evaluating true) than they would be to strings evaluating true.

        (BTW: Sorry about my use of -1 in an earlier post: I had misremembered that c defaulted to -1 for TRUE... But before making this post, I did a quickie in gcc, and saw that 1==1 really did return 1. Maybe I'm remembering some ancient compiler I used 20+ years ago. Or my memory is making this up.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1203405]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2025-11-13 08:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your view on AI coding assistants?





    Results (68 votes). Check out past polls.

    Notices?
    hippoepoptai's answer Re: how do I set a cookie and redirect was blessed by hippo!
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.