Difference between revisions of "Pitfalls"

From IokeWiki
Jump to: navigation, search
m (fnx is activatable but lecrox is unactivatable: typo fixed)
 
(9 intermediate revisions by 3 users not shown)
Line 1: Line 1:
This page collect easy mistakes to do while developing Ioke code. Anything that causes unobvious failures should be listed here. Note that things on this page are not bugs - just things that might be a bit counterintuitive at first glance.
+
This page collect easy mistakes to make while developing Ioke code. Anything that causes unobvious failures should be listed here. Note that things on this page are not bugs - just things that might be a bit counterintuitive at first glance.
  
 
== Mismatched commas ==
 
== Mismatched commas ==
  
One of the most insidious problems that can show up in Ioke programs happen when you forget to add a comma at the right place - or add a comma in a place where there shouldn't be one. Remember, commas separate arguments. Nothing else. Here are some of the most common situations where a mismatched comma will cause the program to work incorrectly - but it will generally still run.
+
One of the most insidious problems that can show up in Ioke programs happens when you forget to add a comma at the right place - or add a comma in a place where there shouldn't be one. Remember, commas separate arguments. Nothing else. Here are some of the most common situations where a mismatched comma will cause the program to work incorrectly - but it will generally still run.
  
 
=== Missing comma after documentation text ===
 
=== Missing comma after documentation text ===
Line 17: Line 17:
  
 
Fixed version:
 
Fixed version:
 +
 
<source lang="ioke">
 
<source lang="ioke">
 
foo = method("foo is a method that does something really cool",
 
foo = method("foo is a method that does something really cool",
Line 23: Line 24:
  
 
The most problematic case is when you have arguments. In that case the omission of the comma will lead to incorrect code that will fail at some point:
 
The most problematic case is when you have arguments. In that case the omission of the comma will lead to incorrect code that will fail at some point:
 +
 
<source lang="ioke">
 
<source lang="ioke">
 
foo = method("foo is a method that does something really cool" x,
 
foo = method("foo is a method that does something really cool" x,
Line 28: Line 30:
 
</source>
 
</source>
  
When foo is called above, you will get either a Condition Error Invocation TooManyArguments, or you will get a Condition Error NoSuchCell. The solution is easy:
+
When <code>foo</code> is called above, you will get either a <code>Condition Error Invocation TooManyArguments</code>, or you will get a <code>Condition Error NoSuchCell</code>. The solution is easy:
 +
 
 
<source lang="ioke">
 
<source lang="ioke">
 
foo = method("foo is a method that does something really cool", x,
 
foo = method("foo is a method that does something really cool", x,
Line 34: Line 37:
 
</source>
 
</source>
  
=== Missing comma in case, cond, if and unless expressions ===
+
=== Missing comma in conditional expressions ===
  
In a case expression, all the different parts of it have to be separated by commas. It is common to use indentation to show which parts belong together, but that is not enough for the Ioke parser to figure things out. A few typical examples where this happens in case, cond, if and unless code:
+
In a case expression, all the different parts of it have to be separated by commas. It is common to use indentation to show which parts belong together, but that is not enough for the Ioke parser to figure things out. A few typical examples where this happens in <code>case</code>, <code>cond</code>, <code>if</code> and <code>unless</code> code:
  
 
<source lang="ioke">
 
<source lang="ioke">
Line 64: Line 67:
  
 
The above should be corrected as:
 
The above should be corrected as:
 +
 
<source lang="ioke">
 
<source lang="ioke">
 
if(foox === 1..3,
 
if(foox === 1..3,
Line 87: Line 91:
 
</source>
 
</source>
  
=== Added comma in dmacro specification ===
+
=== Added comma in <code>dmacro</code> specification ===
 +
 
 +
This problem is the most insidious for the simple reason that it is the opposite of the other comma-related problems. Namely, when writing a <code>dmacro</code>, or one of the other destructuring syntax elements, the problem is generally that you add too many commas:
 +
 
 +
<source lang="ioke">
 +
x = dmacro(
 +
[>foo, bar],
 +
foo + bar evaluateOn(call ground, call ground))
 +
</source>
 +
 
 +
The above code is wrong: there shouldn't be a comma after the square brackets. The <code>dmacro</code> will fail in some spectacular way because of this, but probably not when you expect it. If a <code>dmacro</code> fails for uncertain reasons, and debug-by-printing tells you strange things, the most common cause will be one comma too much. The above code should be:
 +
 
 +
<source lang="ioke">
 +
x = dmacro(
 +
[>foo, bar]
 +
foo + bar evaluateOn(call ground, call ground))
 +
</source>
 +
 
 +
== The [] operator is overloaded in List, Dict and Enumerable ==
 +
 
 +
In most places, the expression
 +
 
 +
<source lang="ioke">
 +
[...]
 +
</source>
 +
 
 +
will create a list: for example,
 +
 
 +
<source lang="ioke">
 +
[]
 +
</source>
 +
 
 +
will create a new, empty list.
 +
 
 +
However, in a method defined on a List, Dict or Enumerable, that code will raise a condition.  So, for example:
 +
 
 +
<source lang="ioke">
 +
List test = method(r = [])
 +
</source>
 +
 
 +
raises the condition "didn't get enough arguments: 1 missing, to '[]' (Condition Error Invocation TooFewArguments)".  This is because in most contexts the [] syntax is used for list creation but in the context of a List, Dict or Enumerable it's used for list lookup instead, allowing us to write things like
 +
 
 +
<source lang="ioke">
 +
r = [1, 2, 3] ; list creation
 +
if(r[1] == 2, ; list lookup
 +
"This is true" println)
 +
</source>
 +
 
 +
The solution is to use
 +
 
 +
<source lang="ioke">
 +
list(...)
 +
</source>
 +
 
 +
instead of
 +
 
 +
<source lang="ioke">
 +
[...]
 +
</source>
 +
 
 +
to create a list in these contexts.
 +
 
 +
== fnx is activatable but lecrox is unactivatable ==
 +
 
 +
Add an x to fn and you get the activatable version of fn.  (fn is unactivatable, with some exceptions.)
 +
 
 +
Add an x to lecro and you get the '''un'''activatable version of lecro.  (lecro is activatable.)
 +
 
 +
== The return value of around advice is used, but the return values of before and after advice is thrown away ==
 +
 
 +
From the guide:
 +
 
 +
''The return value of before and after advice doesn't matter, but the return value of around-advice will be interpreted as the new return value of the message send.''

Latest revision as of 18:20, 13 June 2009

This page collect easy mistakes to make while developing Ioke code. Anything that causes unobvious failures should be listed here. Note that things on this page are not bugs - just things that might be a bit counterintuitive at first glance.

Mismatched commas

One of the most insidious problems that can show up in Ioke programs happens when you forget to add a comma at the right place - or add a comma in a place where there shouldn't be one. Remember, commas separate arguments. Nothing else. Here are some of the most common situations where a mismatched comma will cause the program to work incorrectly - but it will generally still run.

Missing comma after documentation text

When defining a method, macro or syntax with a documentation text, it is very important to remember to add a comma after the text. In most cases the only thing that happens when you forget it is that the object will not get any documentation. But if you continue the expression on the same line you will probably get a signaled condition of some kind.

An example of faulty code:

foo = method("foo is a method that does something really cool"
  42*42)

Fixed version:

foo = method("foo is a method that does something really cool",
  42*42)

The most problematic case is when you have arguments. In that case the omission of the comma will lead to incorrect code that will fail at some point:

foo = method("foo is a method that does something really cool" x,
  42*x)

When foo is called above, you will get either a Condition Error Invocation TooManyArguments, or you will get a Condition Error NoSuchCell. The solution is easy:

foo = method("foo is a method that does something really cool", x,
  42*x)

Missing comma in conditional expressions

In a case expression, all the different parts of it have to be separated by commas. It is common to use indentation to show which parts belong together, but that is not enough for the Ioke parser to figure things out. A few typical examples where this happens in case, cond, if and unless code:

if(foox === 1..3,
  x = 13
  x = :fail)

unless(foxy(42)
  "hello world!" println)

case([p1 value, p2 value],
  [:paper, :rock] win(p1),
  [:rock, :scissors] win(p1),
  [:scissors, :paper] win(p1),
  [:rock, :paper] win(p2),
  [:paper, :scissors] win(p2),
  [:scissors, :rock] win(p2),
  else draw)
    
cond(
  x>10, :foo
  x<5, :bar
  x==7, :fluxie)

Of course, in these examples it is easy to see where the missing commas should go - but in a real program it gets a bit more messy. It has happened several times during the Ioke development process that a bug like this has persisted for a while.

The above should be corrected as:

if(foox === 1..3,
  x = 13,
  x = :fail)

unless(foxy(42),
  "hello world!" println)

case([p1 value, p2 value],
  [:paper, :rock], win(p1),
  [:rock, :scissors], win(p1),
  [:scissors, :paper], win(p1),
  [:rock, :paper], win(p2),
  [:paper, :scissors], win(p2),
  [:scissors, :rock], win(p2),
  else, draw)
    
cond(
  x>10, :foo,
  x<5, :bar,
  x==7, :fluxie)

Added comma in dmacro specification

This problem is the most insidious for the simple reason that it is the opposite of the other comma-related problems. Namely, when writing a dmacro, or one of the other destructuring syntax elements, the problem is generally that you add too many commas:

x = dmacro(
 [>foo, bar],
 foo + bar evaluateOn(call ground, call ground))

The above code is wrong: there shouldn't be a comma after the square brackets. The dmacro will fail in some spectacular way because of this, but probably not when you expect it. If a dmacro fails for uncertain reasons, and debug-by-printing tells you strange things, the most common cause will be one comma too much. The above code should be:

x = dmacro(
 [>foo, bar]
 foo + bar evaluateOn(call ground, call ground))

The [] operator is overloaded in List, Dict and Enumerable

In most places, the expression

[...]

will create a list: for example,

[]

will create a new, empty list.

However, in a method defined on a List, Dict or Enumerable, that code will raise a condition. So, for example:

List test = method(r = [])

raises the condition "didn't get enough arguments: 1 missing, to '[]' (Condition Error Invocation TooFewArguments)". This is because in most contexts the [] syntax is used for list creation but in the context of a List, Dict or Enumerable it's used for list lookup instead, allowing us to write things like

r = [1, 2, 3] ; list creation
if(r[1] == 2, ; list lookup
 "This is true" println)

The solution is to use

list(...)

instead of

[...]

to create a list in these contexts.

fnx is activatable but lecrox is unactivatable

Add an x to fn and you get the activatable version of fn. (fn is unactivatable, with some exceptions.)

Add an x to lecro and you get the unactivatable version of lecro. (lecro is activatable.)

The return value of around advice is used, but the return values of before and after advice is thrown away

From the guide:

The return value of before and after advice doesn't matter, but the return value of around-advice will be interpreted as the new return value of the message send.