Longest string challenge: Difference between revisions

Content added Content deleted
(Go solution)
Line 365: Line 365:
exit(0);
exit(0);
}</lang>
}</lang>
=={{header|Go}}==
<lang go>package main

import (
"bufio"
"os"
)

func main() {
in := bufio.NewReader(os.Stdin)
var blankLine = "\n"
var printLongest func(string) string
printLongest = func(candidate string) (longest string) {
longest = candidate
s, err := in.ReadString('\n')
defer func() {
recover()
defer func() {
recover()
}()
_ = blankLine[0]
func() {
defer func() {
recover()
}()
_ = s[len(longest)]
longest = s
}()
longest = printLongest(longest)
func() {
defer func() {
recover()
os.Stdout.WriteString(s)
}()
_ = longest[len(s)]
s = ""
}()
}()
_ = err.(error)
os.Stdout.WriteString(blankLine)
blankLine = ""
return
}
printLongest("")
}</lang>
Description: It's basically the recursion+exceptions solution used by others, but staying close to the restrictions.

Restriction 1. The program actually has no operators at all, much less comparison operators. By the Go language specification, assignment is a statement, for example, and an index into a string is simply an "index." For this program, comparisons that control program flow are ones that happen during expression evaluation and then either do or do not trigger a run-time panic, the rough equivalent of throwing an exception in other languages.

Restriction 2. No arithmetic is done on numeric types, and in fact there are no variables of any numeric type in the program. While numeric values do appear at points during expression evaluation (the len function, for example) no arithmetic is explicitly done with them. The compiler certainly generates arithmetic instructions for address calculations underlying an index expression, for example; but the source code here simply supplies numbers as indexes, and relies on the compiler to figure out what arithmetic is appropriate.

Restriction 3. Other than integer and string, data types used are:
* Function: Main is a function, and there is extensive use of function literals in the program.
* os.File: os.Stdin and os.Stdout are predefined in package os.
* bufio.Reader: Used to wrap os.Stdin so the convenient ReadString function can be used to get individual input strings.
* error: A predefined type in Go, returned by many library functions (such as bufio.ReadString.)
* byte: While there are no variables of type byte in the program, single byte values appear at various points in expression evaluation. A byte is the result of indexing into a string, for example.

The spirit of the challenge seems to be prohibiting easy ways of doing things until the only ways left are considered novel. I don't consider recursion a particularly novel way of implementing a list, but it's obviously allowed as a solution so I used it. Avoiding arithmetic was fairly easy using the fact that the Go len function returns the length of a string, but that strings are zero based. Thus,
<pre>
if a[len(b)] panics, it means that len(a) <= len(b)
if a[len(b)] does not panic, it means that len(a) > len(b)
</pre>
The above expressions avoid arithmetic, but not all comparisons, because error values are typically tested and branched on. Eliminating all comparisons leaves no boolean values in the program and no way to use if statements, which in Go require a boolean condition. Conditional flow control is implemented with the following device:
<lang go>func() {
// 1. statements executed in either case
// 2. func below is a closure that captures free variables
// now, although the defer statement keeps the function
// from running until later
defer func() {
// 5. function runs either when panic happens, or
// at the time of a normal function return.
recover() // this stops panic mode
// 6. statements executed in either case, just
// before function returns
}()
// 3. more statements executed in either case
// 4. an expression that may or may not panic
// 4a. conditional code. executed only if no panic happens
return // 7. function return happens in either case
}()</lang>
A complication of course is that sometimes you want to conditionally execute code if the expression panics. Without a boolean value to invert, this case requires introducing an extra layer of func..defer..recover with a different expression contrived that will panic with the opposite effect.


=={{header|Icon}} and {{header|Unicon}}==
=={{header|Icon}} and {{header|Unicon}}==