5

The question is how to cope with absence of variable declaration in Python, PHP, and the like.

In most languages there is a way to let the compiler know whether I introduce a new variable or refer to an existing one: my in Perl (use strict) or \newcommand vs. \revewcommand in LaTeX. This prevents from two major sources of errors and headache:

(1) accidentally using the same name of a variable for two different purposes, such as in (PHP)

$v = $square * $height;
<...lots of code...>
foreach ($options as $k => $v)
    echo "For key $k the value is $v\n";
<...lots of code...>
echo "The volume is $v";

or a lot nastier (PHP)

$a = [1, 2, 3];
foreach ($a as $k => &$v)
    $v++;
foreach ($a as $k => $v)
    echo "$k => $v\n";

(can you see a bug here? try it!); and

(2) prevent from typos (PHP):

$option = 1;
$numberofelements = 1;
if ($option)
{
    $numberofelenents = 2;
}
echo $numberofelements;

(can you see a bug here? PHP will execute silently).

Using something like my (Perl)

use strict; 
my $option = 1;
my $numberofelements = 1;
if ($option)
{
    $numberofelenents = 2;
}
say $numberofelements;

(Perl will immediately report the bug) is a tiny effort and HUGE benefit both in debug time and (much more importantly) in losses (potentially huge) from incorrect programs.

However, some languages, notably Python, PHP, and JavaScript, do not give any protection from these types of bugs.

My question is how can we effectively cope with this?

The only way I can foresee is to create two functions (PHP):

function a ($x)
{
    if (isset ($x))
        die();
    else
        return &$x;
}

and

function the ($x)
{
    if (isset ($x))
        return &$x;
    else
        die();
}

and use them always:

a($numberofelements) = 1;
the($numberofelenents)++;
say the($numberofelements);

but of course this is extremely cumbersome. Any better way of effectively protecting from such errors?

No, "use another language", "be careful and don't make errors", and "split your code in tiny functions" are not good answers (the latter may protect from the errors of type 1 but not type 2).

  • The "why" has already been asked [here](http://programmers.stackexchange.com/questions/250467/why-dont-python-and-ruby-make-a-distinction-between-declaring-and-assigning-a-v). – Doval Jul 23 '14 at 13:15
  • @Doval: the main argument on that page is that the only thing that matters is how the code **reads**, and it reads OK without declarations. I totally disagree. I believe the main thing that matters is how the code **executes** (whether it has bugs), and absence of declarations has bitten me quite a number of times. – Alexander Gelbukh Jul 23 '14 at 13:29
  • I agree that the answer contained there may not be satisfactory to you, but you should avoid asking two questions at once, and one of the two you asked is already addressed there. It would be better to take up your objections there than to fork off a new discussion on the same topic here. – Doval Jul 23 '14 at 13:31
  • @Doval: OK, will edit the question to remove the why question and leave only the how question. – Alexander Gelbukh Jul 23 '14 at 13:54
  • Note that `my` in perl is for scoping. Its only with `use strict` that it gains the flavor of declaration. –  Jul 23 '14 at 14:09
  • 1
    +1 for excellent question and for pointing out that this issue costs money because of faulty programs. – Tulains Córdova Jul 24 '14 at 02:40
  • This is one of my number one gripes about Python; I can see no excuse for it. – tchrist Aug 17 '14 at 07:35

3 Answers3

2

In my experience, there are three ways to prevent the problems you described above:

  1. Limit the scope of your variables
  2. Name your variables something meaningful and descriptive
  3. Use a pre-compiler to notify of any errors (Doval mentioned pylint for Python)

1) Limiting the scope of your variables will limit the first error. You will have fewer variables that have the possibility of containing the same name. Odds are that you won't have any collisions. You can limit scope by declaring variables only in the scope that they will be used. The reason this works is because variables will be disposed of as a result of the natural cycle in your code. I've provided an example below for clarify.

class:
    classVariable = "classVar";

    function ThisIsAFunction(functionVar) {
        var functionVar2 = "functionVar2";
        if functionVar > functionVar2 :
            var ifStatementVar = "ifStatementVar";

            for i in range(0,2):
                ifStatementVar += i;
            // i will go out of scope here
        // ifStatementVar will go out of scope here
    // functionVar and functionVar2 will go out of scope here

2) Naming your variables something meaningful will go a long way to preventing re-use of the same variable name. The key in naming your variables is to make them specific enough that their name cannot be reused. When refactoring code it is a good idea to look for function, variable and class names that can be renamed to better reflect their purpose and meaning. An example of good variable names is the following:

function GetSumOfTwoIntegers(intFirstNum, intSecondNum):
    return intFirstNum + intSecondNum;

There is a lot of discrepency when deciding on good names. Everyone has their own style. The main thing to ensure is that you it is clear to yourself and others what the method, parameter or class is supposed to do and be used for. GetSumOfTwoIntegers as a method name tells anyone calling this method that they need to pass in two integers and they will be receiving the sum as a result.

3) Finally, you can use a pre-compiler to tell you of any mistakes that have been made. If you are using a good IDE, it will notify you of any errors. Visual Studio uses Intellisence to let the developer know of any errors before compiling. Most languages have an IDE that supports this functionality. Using one would certainly solve your second problem.

The reason someone might choose to create the syntax of a language in a specific way is hard to determine. I can posture that in Python's case it was likely that the creator wanted to type less when writing code. It only takes a print statement to create a Hello World program in Python. Creating a comparable program in Java requires a lot more typing. Anyways, I don't really know why the creator chose this syntax.

Cameron McKay
  • 316
  • 1
  • 2
  • 8
  • OK, accepting this as answer. Though it's not exactly what I would like: I would like a way to detect typos in the language itself, such as PHP, and not having to use a complicated IDE for this. BTW, creating meaningful (thus, long) names increases the probability of typos; this is why I try to avoid long names. Ironically, it leads to more typing, too: you say the creator of the language wanted to save a couple of keystrokes per new variable and thus forced us to type longer names with every use of the variable, making the program more difficult to type and to read? Then rather stupid of him? – Alexander Gelbukh Jul 23 '14 at 15:04
  • 2
    I think the real reason Python was created is because someone really hated curley braces. Your right, longer names increase the probability of typos. – Cameron McKay Jul 23 '14 at 15:09
  • 1
    I wish he hated parentheses, too. After Perl, I find parentheses a big and unnecessary annoyance and source of bugs. – Alexander Gelbukh Jul 24 '14 at 00:30
2

In addition to the analysis tools, your IDE can also help you suss out these types of issues. I made the move to PyCharm because it handles these types of things much more effectively, than say, Eclipse & PyDev. It is a much more visual IDE that helps you prevent these issues.

Unknown Coder
  • 249
  • 1
  • 8
0

There's only 3 solutions:

  1. Accept that you will occasionally have bugs because of this and deal with them as they occur
  2. Use a lint/static analysis tool (e.g. pylint)
  3. Use another language
Doval
  • 15,347
  • 3
  • 43
  • 58
  • 4. And use meaningful variable names. – eidsonator Jul 23 '14 at 13:25
  • Using meaningful variable names won't protect you from the occasional typo, and going over your code isn't a sure-fire way of spotting said typos since your brain is wired to correct them. I suppose a code review could catch them more reliably than the original writer, but a linter will still do the job better, faster, and is still applicable for one-man projects. – Doval Jul 23 '14 at 13:30
  • Ism't it that protecting from simple errors (not algorithmic ones, but just typos and re-using variable names) is one the **main** purposes or a programming language and a must-have property? – Alexander Gelbukh Jul 23 '14 at 13:32
  • I'm certain many people would disagree; it's not unusual for a C/C++ fan to defend manual memory management on the basis that they don't need a garbage collector to hold their hands. And if you *do* take that position, I question the decision to use dynamic typing, which also lets simple errors through. – Doval Jul 23 '14 at 13:34
  • Even in plain English we use articles for this: "There lived a king. The king had a daughter. The daughter was...": `a` declares an object and `the` indicates a reference. – Alexander Gelbukh Jul 23 '14 at 13:35
  • @Doval: the effort on complex types in C++ is totally incomparable with the tiny effort on `my` in Perl. A language cannot save from all bugs, it's a matter of cost vs. benefit. To say `my` is a tiny cost for huge benefit. – Alexander Gelbukh Jul 23 '14 at 13:40
  • @AlexanderGelbukh The effort involved in using C++ is much bigger than using *other languages in general*, regardless of type system. It's by no means a good example of viable alternatives to dynamic typing. A functional language like OCaml or Haskell or F# would let you write code without spelling out types all over the place but will protect you from simple mistakes like typos, type errors, and `null`. – Doval Jul 23 '14 at 13:44
  • @Doval: You are right. So my question is why so widely used languages as PHP and Python (and thus widely used by less experienced programmers more vulnerable to such errors) do not protect from these errors, as OCaml or Haskell do. And whether there is a way for us to still use those languages (PHP or Python) and guarantee some peace of mind against at least these two kinds of frequent bugs. – Alexander Gelbukh Jul 23 '14 at 13:51