話題の Big Scripting Languages チートシートの Smalltalk の空欄を埋めてみた [前半]
Smalltalk が普通に入っているのがすばらしいですね。せっかくなので、すこしだけ目立ち気味の空欄を GNU Smalltalk、Squeak、VisualWorks で項目を分けてからざっと調べて分かる範囲で埋めてみました。スペースの都合と比較のしやすさから、他の言語は Ruby だけ残してありますので、あしからず。GSTer、VWer は、訂正・補足をお願いします。もちろん Squeak使いからのツッコミも歓迎です。
> | ruby (1995) | GNU Smalltalk (1990) | Squeak (1996; 1983, Apple Smalltalk) | VisualWorks (1993; 1980, XEROX Smalltalk-80) |
---|---|---|---|---|
versions used | 1.8.7; 1.9.1 | 3.2 | 4.1 | 7.7 |
show version | $ ruby --version | Smalltalk version $ gst --version |
Smalltalk version | SystemUtils version |
interpreter | $ ruby foo.rb | $ gst foo.st | none | $ visual your.im -filein script.st |
repl | $ irb | $ gst | use a Workspace | use a Workspace |
check syntax | $ ruby -c foo.rb | none | none | none |
flags for stronger and strongest warnings | $ ruby -w foo.pl $ ruby -W2 foo.pl |
none | none | none |
statement separator | ; or sometimes newline | . (period) or sometimes newline | . (period) | . (period) |
block delimiters | {} or do end | [ ] | [ ] | [ ] |
assignment | a=1 | a := 1 | a := 1 | a := 1 |
parallel assignment | a,b,c = 1,2,3 | none | none | none |
swap | a,b = b,a | | tmp | tmp := a. a := b. b := tmp |
| tmp | tmp := a. a := b. b := tmp |
| tmp | tmp := a. a := b. b := tmp |
compound assignment operators: arithmetic, string, logical, bit | += -= *= /= none %= **= += &&= ||= ^= <<= >>= &= |= ^= |
none | none | none |
increment and decrement | x not mutated: x = 1 x.succ x.pred |
none | none | none |
variable declaration | assignment; $ prefix denotes global scope | Smalltalk at: #GLOBAL put: nil. assignment; will be local to method |
Smalltalk at: #GLOBAL put: nil. for global variable | local1 local2 | for local variable |
Smalltalk at: #GLOBAL put: nil. for global variable | local1 local2 | for local variable |
constant declaration | warns if identifier with uppercase first character is reassigned PI = 3.14 |
none | (Smalltalk associationAt: #GLOBAL) beReadOnlyBinding |
MyNameSpace.MyClass defineSharedVariable: #SharedVar private: false constant: true category: 'SharedVar Category' initializer: '3 + 4' |
end-of-line comment | # comment | none | none | none |
multiline comment | =begin comment line another line =end |
"comment line another line" |
"comment line another line" |
"comment line another line" |
null | nil | nil | nil | nil |
null test | v == nil v.nil? |
v = nil v == nil v isNil |
v = nil v == nil v isNil |
v = nil v == nil v isNil |
undefined variable access | raises NameError | compile error | compile error | compile error |
undefined test | ! defined?(v) | Smalltalk includesKey: #GLOBAL MyClass allClassVarNames includes: #ClassVar |
Smalltalk includesKey: #GLOBAL MyClass allClassVarNames includes: #ClassVar thisContext tempNames includes: #tempVar |
Smalltalk includesKey: #GLOBAL MyClass allClassVarNames includes: #ClassVar thisContext tempNames includes: #tempVar |
arithmetic and logic | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWorks |
true and false | true false | true false | true false | true false |
falsehoods | false nil | false | false | false |
logical operators | and or not also: && || ! | and: or: not always evaluate 2nd operand: & | | and: or: not always evaluate 2nd operand: & | | and: or: not always evaluate 2nd operand: & | |
conditional expression | x > 0 ? x : -x | x > 0 ifTrue: [x] ifFalse: [0 - x] | x > 0 ifTrue: [x] ifFalse: [0 - x] x positive ifTrue: [x] ifFalse: [x negated] |
x > 0 ifTrue: [x] ifFalse: [0 - x] x positive ifTrue: [x] ifFalse: [x negated] |
comparison operators | == != > < >= <= | = ~= > < >= <= | = ~= > < >= <= | = ~= > < >= <= |
convert from string, to string | 7 + "12".to_i 73.9 + ".037".to_f "value: " + "8".to_s |
7 + ‘12’ asNumber 73.9 + '.037' asNumber 'value: ', 8 printString |
7 + ‘12’ asNumber 73.9 + '.037' asNumber 'value: ', 8 printString |
7 + ‘12’ asNumber 73.9 + '.037' asNumber 'value: ', 8 printString |
arithmetic operators | + - * x.fdiv(y) / % ** | + - * / // \\ raisedTo: | + - * / // \\ raisedTo: | + - * / // \\ raisedTo: also: ** |
integer division | a / b | a // b | a // b | a // b |
float division | a.to_f / b or a.fdiv(b) |
a asFloat / b closure of integers under / is the rationals |
a asFloat / b closure of integers under / is the rationals |
a asFloat / b closure of integers under / is the rationals |
arithmetic functions | include Math sqrt exp log sin cos tan asin acos atan atan2 |
sqrt exp ln sin cos tan arcSin arcCos arcTan arcTan: | sqrt exp ln sin cos tan arcSin arcCos arcTan arcTan: | sqrt exp ln sin cos tan arcSin arcCos arcTan arcTan: |
arithmetic truncation | x.abs, x.round, x.ceil, x.floor | x abs. x rounded. x ceiling. x floor | x abs. x rounded. x ceiling. x floor | x abs. x rounded. x ceiling. x floor |
min and max | [1,2,3].min [1,2,3].max |
none | #(1 2 3) min #(1 2 3) max |
#(1 2 3) min #(1 2 3) max |
division by zero | integer division raises ZeroDivisionError float division returns Infinity |
raises ZeroDivide | raises ZeroDivide | raises ZeroDivide |
integer overflow | becomes arbitrary length integer of type Bignum | becomes arbitrary length integer of type LargePositiveInteger | becomes arbitrary length integer of type LargePositiveInteger | becomes arbitrary length integer of type LargePositiveInteger |
float overflow | Infinity | Inf | Infinity | raises OverflowSignal |
sqrt -2 | raises Errno::EDOM | returns NaN | raises FloatingPointException | raises ImaginaryResultSignal |
rational numbers | require 'rational' x = Rational(22,7) x.numerator x.denominator |
x := 22 / 7 x numerator x denominator |
x := 22 / 7 x numerator x denominator |
x := 22 / 7 x numerator x denominator |
complex numbers | require 'complex' z = 1 + 1.414.im z.real z.imag |
PackageLoader fileInPackage: ‘Complex’. z := 1 + 1.414 i z real z imaginary |
z := 1 + 1.414 i z real z imaginary |
load AT MetaNumerics parcel z := 1 + 1.414 i z real z imaginary |
random integer, uniform float, normal float | rand(100) rand none |
rand := Random new rand between: 1 with: 100 rand next next |
rand := Random new 100 atRandom rand next next |
rand := Random new (rand next * 100) asInteger rand next none |
bit operators | << >> & | ^ ~ | bitShift: bitAnd: bitOr: bitXor: bitInvert | << >> bitAnd: bitOr: bitInvert also: bitShift: | bitShift: bitAnd: bitOr: bitXor: bitInvert |
strings | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWroks |
character literal | none | $A | $A | $A |
chr and ord | 65.chr "A".ord |
65 asCharacter $A asciiValue |
65 asCharacter $A asciiValue |
65 asCharacter $A asInteger |
string literal | 'don\'t say "no"' "don't say \"no\"" |
'don''t say "no"' | 'don''t say "no"' | 'don''t say "no"' |
newline in literal | yes | yes (allows multiline) | yes (allows multiline) | yes (allows multiline) |
here document | computer = 'PC' s = <<EOF here document there #{computer} EOF |
none | none | none |
escapes | single quoted: \' \\ double quoted: \a \b \cx \e \f \n \r \s \t \uhhhh \u{hhhhh} \v \xhh \ooo |
none | none | none |
encoding | load the I18N package UTF-8 |
UTF-8 | UTF-8 | |
variable interpolation | count = 3 item = "ball" puts "#{count} #{item}s" |
none | none, use format: or expandMacros count := 3 item := 'ball' '{1} {2}s' format: {count. item} '<1p> <2s>s' expandMacrosWithArguments: {count. item} |
none, use expandMacros count := 3 item := 'ball' '<1p> <2s>s' expandMacrosWith: count with: item |
length | "hello".length "hello".size |
'hello' size | 'hello' size | 'hello' size |
character count | '(3*(7+12))'.count('(') | '(3*(7+12))' occurrencesOf: $( | '(3*(7+12))' occurrencesOf: $( | '(3*(7+12))' occurrencesOf: $( |
index of substring | "foo bar".index("bar") | 'foo bar' indexOfSubCollection: 'bar' | 'foo bar' findString: 'bar' | 'foo bar' findString: 'bar' startingAt: 1 |
extract substring | "foo bar"[4,3] | 'foo bar' copyFrom: 5 to: 7 | 'foo bar' copyFrom: 5 to: 7 | 'foo bar' copyFrom: 5 to: 7 |
concatenate | "hello, " + "world" | 'hello, ', 'world' | 'hello, ', 'world' | 'hello, ', 'world' |
split | "foo bar baz".split | 'foo bar baz' subStrings | 'foo bar baz' subStrings | 'foo bar baz' tokensBasedOn: ' ' |
join | ['foo','bar','baz'].join(' ') | #('foo' 'bar' 'baz') join: ' ' | none, use asStringOn:delimiter: String streamContents: [:ss | #('foo' 'bar' 'baz') asStringOn: ss delimiter: ' '] |
none |
scan | "hello, hep cat".scan(/\w+/) | 'hello, hep cat' allOccurrencesOfRegex: '\w+' | none | none |
pack and unpack | f="a5ilfd" s=["hello",7,7,3.14,3.14].pack(f) s.unpack(f) |
none | none | none |
sprintf | "tie: %s %d %f" % ['Spain',13,3.7] | none | none | none |
case manipulation | "hello".upcase "HELLO".downcase "hello".capitalize |
'hello' asUppercase 'hello' asLowercase none |
'hello' asUppercase 'hello' asLowercase 'hello' capitalized |
'hello' asUppercase 'hello' asLowercase 'hello' capitalized |
strip | " foo ".strip " foo".lstrip "foo ".rstrip |
none | ' foo ' withBlanksTrimmed ' foo' withoutLeadingBlanks 'foo ' withoutTrailingBlanks |
none |
pad on right, on left | "hello".ljust(10) "hello".rjust(10) |
none | 'hello' forceTo: 10 paddingWith: $ 'hello' forceTo: 10 paddingStartWith: $ |
none |
character translation | "hello".tr('a-z','n-za-m') | none | none, use translateWith: | none |
regexp match | "1999".match(/^\d{4}$/) "foo BAR".match(/^[a-z]+/) "foo BAR".match(/[A-Z]+/) |
'1999' =~ '^\d{4}$' 'foo BAR' =~ '^[a-z]+' 'foo BAR' =~ '[A-Z]+' |
none | none |
match, prematch, postmatch | s = "A 17 B 12" while (/\d+/.match(s)) do  discard = $‘  number = $&  s = $’  puts number end |
none, use onOccurrencesOfRegex:do: s := 'A 17 B 12'. s onOccurrencesOfRegex: '\d+' do: [:each | each match displayNl] |
none | none |
substring matches | reg = /(\d{4})-(\d{2})-(\d{2})/ m = reg.match("2010-06-03") yr,mn,dy = m[1..3] |
reg := '(\d{4})-(\d{2})-(\d{2})'. m := '2010-06-03' =~ reg. yr := m at: 1. mn := m at: 2. dy := m at: 3 |
none | none |
single substitution | "teh last of teh Mohicans".sub(/teh/,'the') | 'teh last of teh Mohicans' replacingRegex: 'teh' with: 'the' | none | none |
global substitution | "teh last of teh Mohicans".gsub(/teh/,'the') | 'teh last of teh Mohicans' replacingAllRegex: 'teh' with: 'the' | none | none |
containers | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWorks |
array literal | nums = [1,2,3,4] | nums := #(1 2 3 4) | nums := #(1 2 3 4) | nums := #(1 2 3 4) |
array size | nums.size or nums.length |
nums size | nums size | nums size |
array lookup | nums[0] | nums at: 1 | nums at: 1 | nums at: 1 |
array slice | nums[1..2] | nums copyFrom: 2 to: 3 | nums copyFrom: 2 to: 3 | nums copyFrom: 2 to: 3 |
array iteration | [1,2,3].each { |i| puts i } | nums do: [:o | o displayNl] | nums do: [:o | Transcript cr; show: o] | nums do: [:o | Transcript show: o; cr] |
membership | nums.include?(7) | nums includes: 7 | nums includes: 7 | nums includes: 7 |
intersection | [1,2] & [2,3,4] | none, use select: | #(1 2) intersection: #(2 3 4) | none, use select: |
union | [1,2] | [2,3,4] | none, use asSet | #(1 2) union: #(2 3 4) | none, use asSet |
map | [1,2,3].map { |o| o*o } | #(1 2 3) collect: [:o | o*o] | #(1 2 3) collect: [:o | o*o] | #(1 2 3) collect: [:o | o*o] |
filter | [1,2,3].select { |o| o > 1 } | #(1 2 3) select: [:o | o > 1] | #(1 2 3) select: [:o | o > 1] | #(1 2 3) select: [:o | o > 1] |
reduce | [1,2,3].inject(0) { |m,o| m+o } | #(1 2 3) inject: 0 into: [:m :o| m + o] #(1 2 3) fold: [:m :o | m + o] |
#(1 2 3) inject: 0 into: [:m :o| m + o] | #(1 2 3) inject: 0 into: [:m :o| m + o] #(1 2 3) fold: [:m :o | m + o] |
universal predicate | [1,2,3,4].all? {|i| i.even? } | #(1 2 3 4) allSatisfy: [:o | o even] | #(1 2 3 4) allSatisfy: [:o | o even] | #(1 2 3 4) allSatisfy: [:o | o even] |
existential predicate | [1,2,3,4].any? {|i| i.even? } | #(1 2 3 4) anySatisfy: [:o | o even] | #(1 2 3 4) anySatisfy: [:o | o even] | #(1 2 3 4) anySatisfy: [:o | o even] |
map literal | h = { 't' => 1, 'f' => 0 } | h := Dictionary new add: 't'->1; add: 'f'->0; yourself | h := {'t'->1. 'f'->0} as: Dictionary h := Dictionary new add: 't'->1; add: 'f'->0; yourself |
h := Dictionary new add: 't'->1; add: 'f'->0; yourself |
map size | h.size or h.length |
h size | h size | h size |
map lookup | h['t'] | h at: 't' | h at: 't' | h at: 't' |
is map key present | h.has_key?('y') | h includesKey: 'y' | h includesKey: 'y' | h includesKey: 'y' |
map iteration | h.each { |k,v| code} | h keysAndValuesDo: [:k :v | code] | h keysAndValuesDo: [:k :v | code] | h keysAndValuesDo: [:k :v | code] |
keys and values of map as array | h.keys h.values |
h keys h values |
h keys h values |
h keys h values |
out of bounds behavior | nil | raises IndexOutOfRange | raises error | raises error |
functions | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWorks |
function declaration | def add(a,b); a+b; end | add := [:a :b | a+b] | add := [:a :b | a+b] | add := [:a :b | a+b] |
function invocation | add(1,2) | add value: 1 value: 2 add valueWithArguments: #(1 2) add valueWithArguments: {1. 2} |
add value: 1 value: 2 add valueWithArguments: #(1 2) add valueWithArguments: {1. 2} |
add value: 1 value: 2 add valueWithArguments: #(1 2) |
missing argument | raises ArgumentError | raises WrongArgumentCount | raises error | raises error |
default value | def log(x,base=10) | none | none | none |
arbitrary number of arguments | def add(first, *rest)  if rest.empty? first  else first + add(*rest)  end end |
none | none | none |
named parameter definition | def f(h) | none | none | none |
named parameter invocation | f(:eps => 0.01) | none | none | none |
pass by reference | none | none | none | |
return value | return arg or last expression evaluated | ^ arg or last expression evaluated | ^ arg or last expression evaluated | ^ arg or last expression evaluated |
multiple return values | none | none | none | |
lambda declaration | f = lambda { |x| x * x } | f := [:x | x * x] | f := [:x | x * x] | f := [:x | x * x] |
lambda invocation | f.call(2) | f value: 2 | f value: 2 | f value: 2 |
default scope | local | local | local | local |
nested function definition | not allowed | not allowed (nested method definition) | not allowed (nested method definition) | not allowed (nested method definition) |
execution control | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWorks |
if | if n == 0  puts "no hits" elsif 1 == n  puts "1 hit" else  puts "#{n} hits" end |
(n = 0 ifTrue: ['no hits'] ifFalse: [n = 1 ifTrue: ['1 hit'] ifFalse: [n printString, ' hits']]) displayNl |
Transcript cr; show: (n = 0 ifTrue: ['no hits'] ifFalse: [n = 1 ifTrue: ['1 hit'] ifFalse: [n printString, ' hits']]) or use case-switch like caseOf:otherwise: method Transcript cr; show: ( n caseOf: { [0] -> ['no hits']. [1] -> ['1 hit']} otherwise:[n printString, ' hits']) |
Transcript show: (n = 0 ifTrue: ['no hits'] ifFalse: [n = 1 ifTrue: ['1 hit'] ifFalse: [n printString, ' hits']]); cr |
while | while i < 100 i += 1 |
[i < 100] whileTrue: [i := i + 1] [i >= 100] whileFalse: [i := i + 1] [i := i + 1. i< 100] whileTrue [i := i + 1. i >= 100] whileFalse |
[i < 100] whileTrue: [i := i + 1] [i >= 100] whileFalse: [i := i + 1] [i := i + 1. i< 100] whileTrue [i := i + 1. i >= 100] whileFalse |
[[i < 100] whileTrue: [i := i + 1] [i >= 100] whileFalse: [i := i + 1] [i := i + 1. i< 100] whileTrue [i := i + 1. i >= 100] whileFalse |
break/continue/redo | break, next, redo | none | none | none [:break | [i := i + 1. i > 100 ifTrue: [break value]] repeat ] valueWithExit |
for | none | none; use to:by:do: method 10 to: 1 by: -1 do: [:i | i displayNl ] |
none; use to:by:do: method 10 to: 1 by: -1 do: [:i | Transcript cr; show: i ] |
none; use to:by:do: method 10 to: 1 by: -1 do: [:i | Transcript show: i; cr ] |
range iteration | (1..10).each { |i| puts i } | (1 to: 10) do: [:i | i displayNl] | (1 to: 10) do: [:i | Transcript cr; show: i] | (1 to: 10) do: [:i | Transcript show: i; cr] |
statement modifiers | ||||
raise exception | raise "bad arg" | self error: 'bad arg' | self error: 'bad arg' | self error: 'bad arg' |
catch exception | begin risky rescue puts "risky failed" end |
[risky] ifError: ['risky failed' displayNl] [risky] on: Exception do: ['risky failed' displayNl] |
[risky] ifError: [Transcript cr; show: 'risky failed'] [risky] on: Exception do: [Transcript cr; show: 'risky failed'] |
[risky] on: Exception do: [Transcript show: 'risky failed'; cr] |
finally/ensure | begin acquire_resource risky ensure release_resource end |
[acquireResource. risky] ensure: [eleaseResource] |
[acquireResource. risky] ensure: [eleaseResource] |
[acquireResource. risky] ensure: [eleaseResource] |
uncaught exception behavior | stderr and exit | stderr and exit | notifier | notifier |
start thread | t = Thread.new { sleep 10 } | t := [(Delay forSeconds: 10) wait] fork | t := [10 seconds asDelay wait] fork t := [(Delay forSeconds: 10) wait] fork |
t := [10 seconds wait] fork t := [(Delay forSeconds: 10) wait] fork |
wait on thread | t.join | none, use Semaphore, etc | none, use Semaphore, etc | none, use Semaphore, etc |
environment and i/o | ||||
> | ruby | GNU Smalltalk | Squeak | VisualWorks |
external command | system('ls') | stream := FileDescriptor popen: 'ls' dir: #read. contents := stream contents. stream close. ^contents |
none, use OSProcess package | ExternalProcess new cshOne: 'ls' |
backticks | `ls` | ?? | ?? | ?? |
command line args | ARGV.size, ARGV[0], ARGV[1],… | Smalltalk arguments size, Smalltalk arguments at: 1 | SmalltalkImage current arguments size, SmalltalkImage current argumentAt: 1 | ?? |
print to standard out | puts "hi world" | 'hi world' displayNl | none, use Transcript | load Standard IO Streams parcel OS.Stdout nextPutAll: 'hi world'; cr |
standard file handles | $stdin $stdout $stderr | stdin stdout stderr | none | OS.Stdin OS.Stdout OS.Stderr |
open file | f = File.open('/etc/hosts') or File.open('/etc/hosts') { |f| |
f := FileStream open: '/etc/hosts’. or (File path: '/etc/hosts') withReadStreamDo: [:f | | f := FileStream fileNamed: ‘/etc/hosts’ or FileStream fileNamed: ‘/etc/hosts’ do: [:f | | f := '/etc/hosts' asFilename readStream |
open file for writing | f = File.open('/tmp/test','w') or File.open('/tmp/test','w') { |f| |
f := FileStream open: 'test.txt' mode: #write or (File path: '/etc/hosts') withWriteStreamDo: [:f | | f := FileStream fileNamed: ‘/etc/hosts’ or FileStream fileNamed: ‘/etc/hosts’ do: [:f | | f := '/etc/hosts' asFilename writeStream |
close file | f.close | f close | f close | f close |
read line | f.gets | f nextLine | f nextLine | f upTo: Character cr |
iterate over a file by line | f.each do |line| | f do: [:char | | f do: [:char | | f do: [:char | |
chomp | line.chomp! | none | none | none |
read entire file into array or string | a = f.lines.to_a s = f.read |
s := f contents | s := f contents | s := f contents |
write to file | f.write('hello') | f nextPutAll: ‘hello’ | f nextPutAll: ‘hello’ | f nextPutAll: ‘hello’ |
flush file | f.flush | f flush | f flush | f flush |
environment variable | ENV['HOME'] | Smalltalk getenv: 'HOME' | none, use OSProcess package UnixProcess env at: #HOME |
SystemUtils getEnvironmentVariable: 'HOME’ |
exit | exit(0) | ObjectMemory quit: 0 | none, use SmalltalkIamge current snapshot: false andQuit: true |
ObjectMemory quitWithError: 0 |
set signal handller | Signal.trap("INT", lambda { |signo| puts "exiting…"; exit }) | ?? | none | ?? |
_______________________ | _______________________ | _______________________ | _______________________ |
partially copied from http://hyperpolyglot.wikidot.com/scripting then modified by sumim
and also licensed under Creative Commons Attribution-ShareAlike 3.0