Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re^3: The error says the value is uninitialized, but it works anyway

by Marshall (Canon)
on Aug 20, 2019 at 00:07 UTC ( [id://11104708]=note: print w/replies, xml ) Need Help??


in reply to Re^2: The error says the value is uninitialized, but it works anyway
in thread The error says the value is uninitialized, but it works anyway

I don't rate your prof's assignments very well so far.....

A first Perl class would not normally have any assignment that required using indices of an array, $array[$i] (although list slice which selects a subset of an array would be there, @subset= (@array)[1,5].
Likewise, splice() is something to be mentioned in class, but not used in any assignment.
The reason for that is to get you off C or other programming lingo that you've used before. These constructs while possible in Perl are not that common in a common Perl application, processing textual input line by line.

Dealing with user input is a basic skill that should be taught in the first class. Your prof should have given you a prototype framework of how to do this.... Under "standard" command line input rules, any leading or trailing spaces don't matter.

Below I show how to prompt the user for a number that must contain a decimal point.
We ask the user for a number, get the input from stdin (which may contain spaces), we use regex to decide if the user input line meets the input criteria or not? If the criteria are not met, then the user is re-prompted and we go again...
I like to express this procedure as a single while loop. Note that the parens around the "print" statement are required to get that prompt onto the screen before the rest of the while statement is executed. I also prefer use of the comma operator just from habit and ASM and C background. The comma operator uses the last "sub statement" to determine truth or falsehood. Here an "and" conjunction" would be fine also. Here this difference doesn't really matter at all.

#!/usr/bin/perl use strict; use warnings; print "loops until 4 floats are entered\n"; for (1..4) { my $float = get_float(); print "$float Ok!!\n" } sub get_float { my $float; while ( (print"enter a float \(decimal required\): "), $float = <STDIN>, $float !~ /^\s*(\-|\+)?\d+\.\d*\s*$/) { print "Input not an float...try again\n"; } $float =~ s/^\s*|\s*$//g; #delete leading/trailing spaces return $float; } __END__ perl getfloat.pl loops until 4 floats are entered enter a float (decimal required): 4.5.3 Input not an float...try again enter a float (decimal required): +4,5 Input not an float...try again enter a float (decimal required): +4.5 +4.5 Ok!! enter a float (decimal required): 3 Input not an float...try again enter a float (decimal required): 3.0 3.0 Ok!! enter a float (decimal required): -2.56 -2.56 Ok!! enter a float (decimal required): +3 Input not an float...try again enter a float (decimal required): 3.12345 3.12345 Ok!!
You wrote: "force it to be a floating point number not a string (for math equations)".
Perl is NOT Python!
In simple terms, every Perl variable starts out as a string. Each variable has kind of dual "type", a string value and a numeric value. Unlike Python, you don't have to worry about converting or worrying much about strings vs numeric types - Perl takes care of that for you.

In the above code, I wrote:

$float =~ s/^\s*|\s*$//g; #delete leading/trailing spaces return $float;
That does indeed do what it says it does. Here Perl is using the string version of $float. I did this so that the calling routine will see the "+" sign, which is what the user perhaps entered. Now consider this:
$float +=0; #causes creation of numeric value for $float! return $float;
The plus sign will be missing when printed. Try it!

In general, you don't have to worry about "string" vs "number", Perl will do the right thing without you having to worry about it because there is a duality of values for each variable.

Update: Normally, I would allow an integer input without a decimal to be valid for a "float". Change the regex to eliminate that requirement. Also there is not a Perl "type" for an integer or a float, Perl will figure that difference out for you. There are good things about this and perhaps "bad" things. Usually the programmer doesn't have to worry about the fine details "under the covers".

Oh, just as another comment, your Prof is asking you to do things that haven't been taught in the class yet. A very obvious solution to your assignment is:

#!/usr/bin/perl use strict; use warnings; #The homework question just defines @colors and @drop #and says to remove the things in drop from colors, that's it. my @colors = qw(red green blue yellow pink purple brown); my @drop = qw(pink brown); my %drop = map{$_ =>1}@drop; @colors = grep{!$drop{$_}}@colors; print "@colors \n"; #red green blue yellow purple
Note that both grep and map imply "foreach" loops. They are "hidden", but they are there. A much more verbose version of this will execute in similar time. The assignment is poor because the techniques for the obvious solution for a Perl'er weren't covered in class yet. I also think that it could be that this splice stuff is actually slower!! Splice changes the size of an array and this is a relatively expensive operation. This is not commonly done (except for pop or push) which deal the the beginning or end of an array - not the middle. Making a complete new array with a subset of string values is probably much faster. Underneath Perl is C. An array of strings is to my knowledge an array of pointers to strings. Making a new subset array doesn't involve copying the strings themselves, just their pointers. Changing the size of the array of pointers to strings involves potentially copying a lot of pointers.

Weird thing: I read somewhere in the Perl docs about a "lazy array delete". The element disappears from @array when used in a list context, but the indices of the unaffected elements of @array doesn't change. That sounds "dangerous" albeit much faster than a "splice".

This is more "wordy", but about the same as the shorter version in terms of execution time:

#!/usr/bin/perl use strict; use warnings; #The homework question just defines @colors and @drop #and says to remove the things in drop from colors, that's it. my @colors = qw(red green blue yellow pink purple brown); my @drop = qw(pink brown); my %drop; foreach my $drop (@drop) { $drop{$drop} = 1; ## WILD! Hash and scalar drop ## have separate name spaces! ## I would name different, but ## just a namespace demo... } my @result; foreach my $color (@colors) { push @result, $color unless $drop{$color}; } @colors = @result; print "@colors \n"; #red green blue yellow purple
In Perl the various sigils, @,%,$ have their own namespaces. This is not true in many other languages (C,Python). Be aware of that and in general do not use the exact same name for different Perl types. Above I showed how confusing this could be! Just because it is allowed doesn't mean you should do it!

You wrote: "I could only find a way to take user input and make it an integer" Study the above. If a variable is an valid integer string, you can use it as a numeric value! No conversion is required! A $variable can be pretty much be used interchangeably. as a number (int or float) or string.

Replies are listed 'Best First'.
Re^4: The error says the value is uninitialized, but it works anyway
by hippo (Bishop) on Aug 20, 2019 at 09:15 UTC
    In simple terms, every Perl variable starts out as a string.

    I have never heard this before. Do you have a source for this, please?

      Well "simple terms" were perhaps too simple. This is not true if you have a program statement say $x=32; In the context of the question being asked (inputing a value from the console), this is true and I discussed some of the ramifications of that and gave demo code. In the subroutine that prompts for the float... In version #1, I just strip off the leading and trailing spaces with a regex. The returned value is a string. However, as I point out an alternate way to "strip off the white space" (sort of) is to force Perl to convert the string to a numeric value. You can do this by simply adding 0 to it. $float+=0; When you do this to an int value, it is pretty much like stripping the whitespace. However with a float, there will be usual storage imprecision and possible extension digits after the decimal. 6.3 might be 6.33333333, etc. As I point out, if you had inputted say "+5.0", if you use the "add 0" method, the plus sign will not be there when printed out in the calling routine because Perl will be using the numeric value, not the string value we started with. Of course when inputting a string and doing math upon it, you have to ensure the string is a valid number, else there will be at least some kind of warning message generated!

      The important point for the OP which perhaps got lost, is that you don't have to call any special function to cause the conversion to a numeric value - in some languages you do, but not in Perl. (In C you could use a %f format spec for the read and there is no string value, you get a binary number straight away). In Perl there will be a string value and you just do math on that string and Perl will do "the right thing".

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-23 23:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found