Friday, September 11, 2009

use of goto versus runtime code evaluation

Asked on stackoverflow.com: http://stackoverflow.com/questions/1412620/use-of-goto-versus-runtime-code-evaluation

----
2
Recently for a programming class, we were given the assignment to write a program in any language that, given n, will produce all the possible derangements for an array p of size n such that p[i] != i for all i: 0 <= i < n. We had to use iterators, e.g. yield.
Example: n=3, [0, 1, 2] is not a derangement, but [2, 0, 1] is as well as [1, 2, 0].
I came up with a pseudocode solution that would work, but the problem was that it required power loops (that is, n nested loops where n is only known at runtime). To do this, I generated n nested loops in Ruby code in a string, then eval-ed the string. My solution worked, however my professor thought that using a few gotos would have been better solution (easier to read, at least) than dynamic code generation.
I was under the impression that goto was always a bad choice. Why might runtime evaluation of dynamically generated code be a worse choice than goto? The generated code is clean and simple, and seems fairly efficient for the given problem. The only user input upon which the code generation depends is n, which is checked to ensure it's an integer value beforehand. It yields only unique derangements, as it should.
I'm not asking for a solution to my programming assignment, I just want to know reasons behind the use of goto over dynamic code evaluation, or vice versa.
Edit: to clarify, the assignment included writing a program using iterators and another using recursion, so the iterative version wasn't necessarily meant to be efficient.


---------------
My responses:

Here's a solution with early pruning. Mhy only question is regarding enumerations: did he want you to create an enumerator that on each successful call would generate the next item in the list? This would probably be easiest implemented by creating a lambda version of this program - I used to do this in lisp all the time when writing query generators that would generate the next answer to a question when doing prolog-interpreter style queries.

-----

Non-recursive version using goto:

Option Strict On
Option Explicit On
Module Module1
Dim x As Stack
Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
For Each el In generatedList
Console.Write(el & " ")
Next
Console.WriteLine()
End Sub
Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
ByVal generatedList As List(Of Integer))
Dim stackI As Stack(Of Integer) = New Stack(Of Integer)
Dim stackJ As Stack(Of Integer) = New Stack(Of Integer)
Dim j As Integer
StartLabel:
j = 0
If i >= n Then
printGeneratedList(generatedList)
If stackI.Count = 0 Then
Return
Else
GoTo ReturnLabel
End If
Return
End If
While j < n
If Not j = i Then
If Not generatedList.Contains(j) Then
generatedList.Add(j)
stackI.Push(i)
stackJ.Push(j)
i = i + 1
GoTo StartLabel
ReturnLabel:
i = stackI.Pop()
j = stackJ.Pop()
generatedList.Remove(j)
End If
End If
j = j + 1
End While
If stackI.Count = 0 Then
Return
Else
GoTo ReturnLabel
End If
End Sub
Private Sub generate(ByVal n As Integer)
Console.WriteLine("Generating for n = " & n.ToString())
Dim l As List(Of Integer) = New List(Of Integer)
If n < 0 Then
Throw New Exception("n must be >= 0")
End If
generateAux(0, n, l)
End Sub
Sub Main()
generate(0)
Console.ReadLine()
generate(1)
Console.ReadLine()
generate(2)
Console.ReadLine()
generate(3)
Console.ReadLine()
generate(4)
Console.ReadLine()
End Sub
End Module

--------------

Recursive version:
Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
ByVal generatedList As List(Of Integer))
If i >= n Then
printGeneratedList(generatedList)
Return
End If
For j As Integer = 0 To n - 1
If Not j = i Then
If Not generatedList.Contains(j) Then
generatedList.Add(j)
generateAux(i + 1, n, generatedList)
generatedList.Remove(j)
End If
End If
Next
End Sub

No comments:

Post a Comment