Swift vs. C# : The Basic


- お勉強を始めて見ました

# Version

~~~
$ xcodebuild -version
Xcode 6.0.1
Build version 6A317
~~~

~~~
Peeko:Documents hide$ mono --version
Mono JIT compiler version 3.8.0 ((no/45d0ba1 Tue Aug 26 20:33:43 EDT 2014)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
	TLS:           normal
	SIGSEGV:       altstack
	Notification:  kqueue
	Architecture:  x86
	Disabled:      none
	Misc:          softdebug 
	LLVM:          yes(3.4svn-mono-(no/e656cac)
	GC:            sgen
~~~

# REPL


~~~
Peeko:Documents hide$ xcrun --sdk iphonesimulator8.0 swift
Welcome to Swift!  Type :help for assistance.
  1> ^D
~~~

~~~
Peeko:Documents hide$ csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp>  
~~~

# var


~~~
  1> var msg ="hello"
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2010/repl1.swift:2:9: error: prefix/postfix '=' is reserved
var msg ="hello"
        ^

  1> var msg="hello"
msg: String = "hello"

  2> var msg= "hello"
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2010/repl4.swift:2:8: error: prefix/postfix '=' is reserved
var msg= "hello"
       ^
~~~

~~~
 21> var i = 3, j=4, k=5;
i: Int = 3
j: Int = 4
k: Int = 5
~~~

~~~
csharp> var msg = "hello";
~~~

~~~
csharp> var i = 3, j= 4, k=5;
(1,2): error CS0819: An implicitly typed local variable declaration cannot include multiple declarators
~~~

# var:Type Annotations

~~~
 22> var i:Int = 3;
i: Int = 3
~~~

~~~
csharp> int i=3;
csharp> i
3
~~~

# println() = Console.WriteLine()

~~~
  2> println(msg)
hello
~~~

~~~
csharp> Console.WriteLine(msg);
hello
~~~

# let = const

~~~
  3> let BYE="goodbye"
BYE: String = "goodbye"
  4> BYE="GOODBYE"
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2010/repl9.swift:2:4: error: cannot assign to 'let' value 'BYE'
BYE="GOODBYE"
~~~^
~~~

~~~
csharp> class Message { public const string BYE="goodbye";}
csharp> Message.BYE;
"goodbye"
csharp> Message.BYE = "GOODBYE";
(1,10): error CS0131: The left-hand side of an assignment must be a variable, a property or an indexer
~~~


#  strongly typed

~~~
  4> msg=3
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2010/repl10.swift:2:4: error: type 'String' does not conform to protocol 'IntegerLiteralConvertible'
msg=3
   ^
~~~

~~~
csharp> MSG=3;
(1,6): error CS0029: Cannot implicitly convert type `int' to `string'
~~~

# concat strings

~~~
  4> msg += ", it's me."
  5> msg
$R0: String = "hello, it's me."
~~~

~~~
csharp> msg += ", it's me.";
csharp> msg
"hello, it's me."
~~~

# ;

~~~
  6> msg += " by Isley"; msg += "Brothers"
  7> msg
$R1: String = "hello, it's me. by IsleyBrothers"
~~~

~~~
csharp> msg += " by Isley"; msg += "Brothers"; 
csharp> msg
"hello, it's me. by IsleyBrothers"
~~~

# //

~~~
  9> var msg = "hello" // Hello
msg: String = "hello"
~~~

~~~
csharp> var msg = "hello"; // Hello
csharp> msg
"hello"
~~~


# nil = null

~~~
 31> var msg:String?
msg: String? = nil
 32> msg == nil
$R11: Bool = true
~~~

~~~
csharp> string msg = null;
csharp> msg == null;
true
~~~~

# as

ちょっと深そう。。。

~~~
  8> 10 as Double
$R2: Double = 10

  9> 10.0 as Int
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2950/repl22.swift:2:6: error: 'Double' is not convertible to 'Int'
10.0 as Int
     ^
~~~     

~~~
csharp> "hoge" as string
"hoge"
csharp> 2 as int
(1,4): error CS0077: The `as' operator cannot be used with a non-nullable value type `int'
~~~


# is

自明なのでコンパイラがエラー

~~~
 20> var msg = "hello" 
msg: String = "hello"
 21> msg is String
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2417/repl63.swift:2:5: error: 'is' test is always true
msg is String

 21> var msg:String
msg: String = ""
 22> msg is String
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/2417/repl66.swift:2:5: error: 'is' test is always true
msg is String
    ^
~~~

不明な変数で定義する

~~~
 23> var msg:Any?
msg: Any? = nil
 24> msg="hello"
 25> msg is String
$R8: Bool = true
~~~


ちなみに

~~~
 44> println(msg)
Optional("hello")
~~~


~~~
csharp> "hello" is string;
(1,10): warning CS0183: The given expression is always of the provided (`string') type
true
~~~

~~~
csharp> var msg="hello";
csharp> msg is string;
true
~~~

C#はすべてオブジェクトなのでGetType()できる

~~~
csharp> msg.GetType() == typeof(string);
true
csharp> "hello".GetType() == typeof(string);
true
~~~

# Any?  / object

何でもアサインできます

~~~
  1> var msg:Any="Bootsy"
Segmentation fault: 11
Peeko:Documents hide$ xcrun --sdk iphonesimulator8.0 swift
Welcome to Swift!  Type :help for assistance.
  1> var msg:Any?="Bootsy"
msg: Any? = Some {
  payload_data_0 = {}
  payload_data_1 = {}
  payload_data_2 =
  instance_type = {}
}
  2> msg=2
~~~

キャストします

~~~
  3> msg as Int == 2
$R0: Bool = true
  4> msg as String
Execution interrupted. Enter Swift code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
  5> msg="Funk"
  6> msg as String == "Funk"
$R1: Bool = true
~~~

~~~
csharp> object msg;
csharp> msg="Func";
csharp> msg.ToString()
"Func"
csharp> msg=2;
csharp> msg.ToString()
"2"

csharp> msg = msg + 3
(1,8): error CS0019: Operator `+' cannot be applied to operands of type `object' and `int'

csharp> msg = 2
csharp> msg = 2; 
csharp> (int)msg + 3;
5

~~~
  
# _

まじで

~~~
  9> 1_000_000
$R3: Int = 1000000
~~~

~~~
csharp> using System.Globalization;
csharp> var ci = CultureInfo.GetCultureInfo("ja-JP").NumberFormat; 
csharp> Double.Parse("1,234.33",ci) 
1234.33    
~~~

# tuple

~~~
 15> var x = (1, 2, 3)
x: (Int, Int, Int) = {
  0 = 1
  1 = 2
  2 = 3
}
 16> x.0
$R8: Int = 1
 17> x.1
$R9: Int = 2
 18> x.2
$R10: Int = 3
~~~

~~~
csharp> var x = new Tuple<int, int, int>(1, 2, 3);
csharp> x.Item1
1
csharp> x.Item2
2
csharp> x.Item3
3
~~~

# Format strings

~~~
 19> var i=3
i: Int = 3
 20> "\(i)"
$R11: String = "3"
~~~

~~~
csharp> var i=3;
csharp> string.Format("{0}", i);
"3"
~~~

# Integers

~~~
 31> var data:(UInt, UInt8, UInt16, UInt32, UInt64)=(UInt.max, UInt8.max, UInt16.max, UInt32.max, UInt64.max)
data: (UInt, UInt8, UInt16, UInt32, UInt64) = {
  0 = 18446744073709551615
  1 = 255
  2 = 65535
  3 = 4294967295
  4 = 18446744073709551615
}

 32> var data:(Int, Int8, Int16, Int32, Int64)=(Int.min, Int8.min, Int16.min, Int32.min, Int64.min)
data: (Int, Int8, Int16, Int32, Int64) = {
  0 = -9223372036854775808
  1 = -128
  2 = -32768
  3 = -2147483648
  4 = -9223372036854775808
}
~~~

~~~
csharp> new Tuple<int, SByte,Int16, Int32, Int64>(int.MinValue, SByte.MinValue, Int16.MinValue, Int32.MinValue, Int64.MinValue);
(-2147483648, -128, -32768, -2147483648, -9223372036854775808)

csharp> new Tuple<uint, Byte,UInt16, UInt32, UInt64>(uint.MaxValue, Byte.MaxValue, UInt16.MaxValue, UInt32.MaxValue, UInt64.MaxValue);
(4294967295, 255, 65535, 4294967295, 18446744073709551615)
~~~~

# Numeric Literals

~~~
 33> ("decimal", 3)
$R12: (String, Int) = {
  0 = "decimal"
  1 = 3
}

 35> ("binary", 0b11111110)
$R14: (String, Int) = {
  0 = "binary"
  1 = 254
}

 37> ("octal", 0o17)
$R16: (String, Int) = {
  0 = "octal"
  1 = 15
}
 38> ("hex", 0x33)
$R17: (String, Int) = {
  0 = "hex"
  1 = 51
}

 40> ("exponent 1.25 x 10^2", 1.25e2)
$R19: (String, Double) = {
  0 = "exponent 1.25 x 10^2"
  1 = 125
}

 41> 0xfp2
$R20: Double = 60
 42> 0xfp-2
$R21: Double = 3.75
~~~

~~~
csharp> string.Format("decimal {0}", 3) 
"decimal 3"

csharp> string.Format("binary {0}",Convert.ToInt32("11111110", 2))
"binary 254"

csharp> string.Format("oct {0}",Convert.ToInt32("17", 8) ) 
"oct 15"

csharp> string.Format("hex {0}", 0x33)
"hex 51"

csharp> using System.Globalization;
csharp> string.Format("exponent 1.25 x 10^2 {0}", double.Parse("1.25e2", CultureInfo.InvariantCulture)) 
"exponent 1.25 x 10^2 125"

csharp> string.Format("15x2^2 {0}", Math.Pow(2, 2) * 15)
"15x2^2 60"
csharp> string.Format("15x2^-2 {0}", Math.Pow(2, -2) * 15)
"15x2^-2 3.75"

~~~

# Optionals

- nil がありえる変数は "optional"変数

Options:

- There is a value, and it equals x (値があって何かと等価)
- There isn’t a value at all(値が全くない)

Int?がオプショナル:

~~~
  1> let possibleNumber = "123"
possibleNumber: String = "123"
  2> let convertedNumber = possibleNumber.toInt()
convertedNumber: Int? = 123
~~~

~~~
  3> "123".toInt()
$R0: Int? = 123
  4> "abc".toInt()
$R1: Int? = nil
~~~

## nil

- optionalにはnilをセットできる

~~~
  5> var i: Int? = nil
i: Int? = nil
~~~

~~~
  1> var j:Int = nil
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/34261/repl1.swift:2:13: error: type 'Int' does not conform to protocol 'NilLiteralConvertible'
var j:Int = nil
            ^
~~~


C#

~~~
csharp> int? i = null;
csharp> i = 3
csharp> i
3
csharp> int j = null;
(1,10): error CS0037: Cannot convert null to `int' because it is a value type
~~~

## If Statements and Forced Unwrapping

! : forced unwrapping (強制取り出し)


- ifでnil判定

~~~
  1> if "abc".toInt() != nil { 
  2.   println("abc is converted to Int"); 
  3. } 
  4. else{ 
  5.   println("abc is not converted to Int"); 
  6. }
abc is not converted to Int
~~~


- optional の値があれば、"!" を付けて参照可能 (forced unwrapping)

~~~
  7> var j: Int? = "123".toInt()
j: Int? = 123

 10> println(j)
Optional(123)
 11> println(j!)
123
~~~

C#: 普通に参照

~~~
csharp> int? i = null;
csharp> if( i == null ) { Console.WriteLine("i is null"); }
i is null

csharp> i = 3
csharp> i = null
csharp> i
null
~~~

~~~
csharp> var j = 3 
csharp> j = null
(1,6): error CS0037: Cannot convert null to `int' because it is a value type
~~~

## Optional Binding

optional binding : ifとかでoptionalに値があるかどうかを判定できる手段

~~~
  2. var x = "abc" 
  3. if let i = x.toInt() { 
  4.   println("\(x) is Int") 
  5. } 
  6. else{ 
  7.   println("\(x) is not Int") 
  8. }
abc is not Int

x: String = "abc"
~~~

~~~
  1> var x = "123" 
  2. if let i = x.toInt() { 
  3.   println("\(x) is Int") 
  4. } 
  5. else{ 
  6.   println("\(x) is not Int") 
  7. }
123 is Int

x: String = "123"
~~~

## implicitly Unwrapped Optionals


"!" = implicitly unwrapped optionals

> Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. 

> The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties.

~~~
  1> var i :String? = "Hello"
i: String? = "Hello"
  2> var j :String! = "Goodbye"
j: String! = "Goodbye"
  3> "\(i)"
$R0: String = "Optional(\"Hello\")"
  4> "\(i!)"
$R1: String = "Hello"
  5> "\(j)"
$R2: String = "Goodbye"
~~~

~~~
  6> i = nil
  7> j = nil
  8> i == nil
$R3: Bool = true
  9> j == nil
$R4: Bool = true
 10> var k : String
k: String = ""
 11> k == nil
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/35236/repl21.swift:2:3: error: cannot invoke '==' with an argument list of type '(@lvalue String, NilLiteralConvertible)'
k == nil
~~^~~~~~
~~~

!変数は参照される時に必ず自動的にアンラップされる?変数、みたいなもの

> You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. 

あとでnilになりそうであれば、 !ではなく通常のオプショナル(?)を使え、とのこと

> Do not use an implicitly unwrapped optional when there is a possibility of a variable becoming nil at a later point. 

> Always use a normal optional type if you need to check for a nil value during the lifetime of a variable.


# Assertions


## Debugging with Assertions


Swift:

~~~
 11> let age = -3
age: Int = -3
 12> assert(age >= 0, "A person's age cannot be less than zero")
~~~
~~~
assertion failed: A person's age cannot be less than zero: file /var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/35236/repl24.swift, line 12
Execution interrupted. Enter Swift code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
~~~

C#:

~~
System.Diagnostics.Debug.Assert(
   age >= 0 , 
   "A person's age cannot be less than zero"
);
~~

Monoだと、

~~~
System.Diagnostics.Debug.Listeners.Add ( 
    new System.Diagnostics.ConsoleTraceListener()
)
~~~

とかしないといけないので、普通にExceptionだすチェッカー　を用意するのがいい

~~~
[Conditional("DEBUG")] 
public static void Assert(bool predicate, string msg)
{
	if( predicate == false ) throw new Exception(msg);
}
~~~

## When to Use Assertions

- 他言語と同じ