-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.html
974 lines (818 loc) · 39.2 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
<!DOCTYPE html><html><head><title>Kotlin is like C#</title><meta charset="utf-8"><meta name="description" content="Kotlin vs C#. Compare the syntax of Kotlin and C# through short code examples."><link rel="icon" href="https://kotlinlang.org/assets/images/favicon.ico" type="image/x-icon"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/github.min.css"><style>body {
font-family: "Helvetica Neue", sans-serif;
margin: 0;
}
body * {
box-sizing: border-box;
}
.section {
background-color: #f4f4f4;
padding: 4em 3em;
}
.section:nth-child(2n) {
background-color: white;
}
.title {
font-size: 2.7em;
color: #888;
font-weight: 100;
letter-spacing: 0.2em;
text-align: center;
}
.case {}
.name {
font-size: 1.8em;
color: #444;
font-weight: 300;
text-align: center;
margin: 60px;
}
.pair {
display: flex;
display: -webkit-flex;
display: -ms-flexbox;
justify-content: center;
-webkit-justify-content: center;
-ms-box-pack: center;
-ms-box-align: center;
}
.card {
flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
width: 50%;
max-width: 650px;
margin: 0 10px;
}
.lang {
font-size: 1.3em;
color: #666;
padding-bottom: 0;
font-weight: 200;
letter-spacing: 0.07em;
}
.code {
font-size: 1.15em;
background-color: white;
margin: 0.4em 0 0 0;
padding: 0.4em;
line-height: 1.3em;
}
.section:nth-child(2n) .code {
background-color: #f4f4f4;
}
#fork-me {
position: absolute;
right: 0;
}
.hljs {
background-color: transparent;
}
#note {
font-size: 1.5em;
color: #fff;
text-align: center;
padding: 0.6em;
background: #414141;
font-weight: 300;
letter-spacing: 0.05em;
}
.disclaimer {
font-size: 0.8em;
text-align: center;
padding: 0.6em;
font-weight: 300;
letter-spacing: 0.05em;
}
</style><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/highlight.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/languages/kotlin.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/languages/cs.min.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><a target="_blank" href="https://github.com/ttu/kotlin-is-like-csharp"><img id="fork-me" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149"></a><div id="note">Kotlin is like C#</div><div class="disclaimer">Compare the syntax of Kotlin vs C#. Don't take language likeness comparison too seriously.</div><div class="disclaimer">Fixes, improvents and additions are welcome. Open an issue or a pull request.</div><div class="section"><div class="title">BASICS</div><div class="case"><div class="name">Hello World</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>println("Hello, world!")
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>public void Main()
{
Console.WriteLine("Hello, world!");
}
// C# 9 supports top-level statements
Console.WriteLine("Hello, world!");</code></pre></div></div></div><div class="case"><div class="name">Variables and Constants</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>var myVariable = 42
myVariable = 50
val myConstant = 42
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var myVariable = 42;
myVariable = 50;
// C# doesn't have local runtime constants
</code></pre></div></div></div><div class="case"><div class="name">Explicit Types</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val explicitDouble: Double = 70.0
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>double explicitDouble = 70.0;
</code></pre></div></div></div><div class="case"><div class="name">Type Coercion</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val label = "The width is "
val width = 94
val widthLabel = label + width
// The width is 94</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var label = "The width is ";
var width = 94;
var widthLabel = label + width;
// The width is 94</code></pre></div></div></div><div class="case"><div class="name">Compile Time Constants</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>const val SYSTEM_DEPRECATED: String = "System is deprecated"</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>const string SYSTEM_DEPRECATED = "System is deprecated";</code></pre></div></div></div><div class="case"><div class="name">String Interpolation</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val apples = 3
val oranges = 5
val fruitSummary = "I have ${apples + oranges} " +
"pieces of fruit."
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var apples = 3;
var oranges = 5;
var fruitSummary = $"I have {apples + oranges} " +
"pieces of fruit.";
</code></pre></div></div></div><div class="case"><div class="name">If Expression / Statement</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val age = 42
if (age < 10) {
println("You're too young to watch this movie")
} else if (age < 13) {
println("You can watch this movie with a parent")
} else {
println("You can watch this movie")
}</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var age = 42;
if (age < 10)
{
Console.WriteLine("You're too young to watch this movie");
}
else if (age < 13)
{
Console.WriteLine("You can watch this movie with a parent");
}
else
{
Console.WriteLine("You can watch this movie");
}</code></pre></div></div></div><div class="case"><div class="name">Conditionals</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// if is an expression, so ternary operation not needed
val loaded = true
val status = if (loaded) "Ready" else "Loading..."
// "Ready</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var loaded = true;
var status = loaded ? "Ready" : "Loading...";
// "Ready</code></pre></div></div></div></div><div class="section"><div class="title">FUNCTIONS</div><div class="case"><div class="name">Functions</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun greet(name: String, day: String): String {
return "Hello $name, today is $day."
}
val text = greet("Bob", "Tuesday")
// Hello Bob, today is Tuesday.</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>string Greet(string name, string day)
{
return $"Hello {name}, today is {day}.";
}
var text = Greet("Bob", "Tuesday");
// Hello Bob, today is Tuesday</code></pre></div></div></div><div class="case"><div class="name">Single Expression Functions</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Single expression functions can be without braces and return type
fun double(value: Int) = value * 2
val result = double(4)
// 8</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Single expression functions can be without braces
int Double(int value) => value * 2;
var result = Double(4);
// 8</code></pre></div></div></div><div class="case"><div class="name">Named Arguments</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun area(width: Int, height: Int) = width * height
var result = area(width = 2, height = 3)
// This is also possible with named arguments
result = area(2, height = 2)
result = area(height = 3, width = 2)
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>int Area(int width, int height) => width * height;
var result = Area(width: 2, height: 3);
// This is also possible with named arguments
result = Area(2, height: 2);
result = Area(height: 3, width: 2);</code></pre></div></div></div><div class="case"><div class="name">Default Arguments</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun displayGreeting(message: String, name: String = "Guest") {
println("Hello $name, $message")
}
displayGreeting("welcome!")
// Hello Guest, welcome!</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>void DisplayGreeting(string message, string name = "Guest")
{
Console.WriteLine($"Hello {name}, {message}");
}
DisplayGreeting("welcome!");
// Hello Guest, welcome!</code></pre></div></div></div><div class="case"><div class="name">Variable Number of Arguments</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun sumOf(vararg numbers: Int): Int {
var sum = 0
for (number in numbers) {
sum += number
}
return sum
}
val sum = sumOf(42, 597, 12)
// sumOf() can also be written in a shorter way:
fun sumOf(vararg numbers: Int) = numbers.sum()
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>int SumOf(params int[] numbers)
{
var sum = 0;
foreach (var number in numbers)
sum += number;
return sum;
}
var sum = SumOf(42, 597, 12);
// SumOf() can also be written in a shorter way:
int SumOf(params int[] numbers) => numbers.Sum();</code></pre></div></div></div><div class="case"><div class="name">Lambdas</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun containsEven(numbers: List<Int>) = numbers.any { it % 2 == 0 }</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>bool ContainsEven(List<int> numbers) => numbers.Any(e => e % 2 == 0);</code></pre></div></div></div><div class="case"><div class="name">Higher-Order Functions - Return a Function</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun makeIncrementer(): (Int) -> Int {
val addOne = fun(number: Int): Int {
return 1 + number
}
return addOne
}
val increment = makeIncrementer()
val result = increment(7)
// makeIncrementer can also be written in a shorter way:
fun makeIncrementer() = fun(number: Int) = 1 + number
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>Func<int, int> MakeIncrementer()
{
int addOne(int number) => 1 + number;
return addOne;
}
var increment = MakeIncrementer();
var result = increment(7);
// MakeIncrementer can also be written in a shorter way:
Func<int, int> MakeIncrementer() => i => 1 + i;
</code></pre></div></div></div><div class="case"><div class="name">HOF - Function as Parameter</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun transform(initial: String, f: (String) -> String) = f(initial)
val result = transform("hello", { x -> x.toUpperCase() })
// HELLO
// Trailing lambda can be placed outside the parentheses
val result2 = transform("hello") { x -> x.toUpperCase() }</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>string Transform(string initial, Func<string, string> f) => f(initial);
var result = Transform("hello", x => x.ToUpper());
// HELLO</code></pre></div></div></div><div class="case"><div class="name">Tuple Return</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Kotlin doesn't have tuples, use data classes
data class GasPrices(val a: Double, val b: Double, val c: Double)
fun getGasPrices() = GasPrices(3.59, 3.69, 3.79)
val prices = getGasPrices();
val (a, b, c) = getGasPrices();</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>(double a, double b, double c) GetGasPrices() => (3.59, 3.69, 3.79);
var result = GetGasPrices();
var (a, b, c) = GetGasPrices();</code></pre></div></div></div></div><div class="section"><div class="title">COLLECTIONS</div><div class="case"><div class="name">Arrays</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val shoppingList = arrayOf("catfish", "water",
"tulips", "blue paint")
shoppingList[1] = "bottle of water"
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var shoppingList = new[] { "catfish", "water",
"tulips", "blue paint" };
shoppingList[1] = "bottle of water";</code></pre></div></div></div><div class="case"><div class="name">Lists</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val shoppingList = listOf("catfish", "water",
"tulips", "blue paint")
val shoppingListMutable = mutableListOf("catfish", "water",
"tulips", "blue paint")
shoppingListMutable[1] = "bottle of water"
shoppingListMutable.add("bucket")
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>IReadOnlyList<string> shoppingList = new List<string> { "catfish",
"water", "tulips", "blue paint" };
var shoppingListMutable = new List<string> { "catfish", "water",
"tulips", "blue paint" };
shoppingListMutable[1] = "bottle of water";
shoppingListMutable.Add("bucket");</code></pre></div></div></div><div class="case"><div class="name">Maps / Dictionaries</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val occupations = mapOf(
"Malcolm" to "Captain",
"Kaylee" to "Mechanic"
)
val occupationsMutable = mutableMapOf(
"Malcolm" to "Captain",
"Kaylee" to "Mechanic"
)
occupationsMutable["Jayne"] = "Public Relations"
occupationsMutable.put("Rick", "Navigation")
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>IReadOnlyDictionary<string,string> occupations =
new Dictionary<string, string>
{
["Malcolm"] = "Captain",
["Kaylee"] = "Mechanic"
};
var occupationsMutable = new Dictionary<string, string>
{
["Malcolm"] = "Captain",
["Kaylee"] = "Mechanic"
};
occupationsMutable["Jayne"] = "Public Relations";
occupationsMutable.Add("Rick", "Navigation");
</code></pre></div></div></div><div class="case"><div class="name">Empty Collections</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val emptyList = mutableListOf<String>()
val emptyMap = mutableMapOf<String, Float>()
// read-only empty list
val empty = emptyList<String>()</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var emptyList = new List<string>();
var emptyDictionary = new Dictionary<string, float>();
// read-only empty list
var empty = Enumerable.Empty<string>();</code></pre></div></div></div><div class="case"><div class="name">ForEach</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val names = arrayOf("Anna", "Alex", "Brian", "Jack")
for (name in names) {
println("Person is called $name")
}
names.forEach { println("Person is called $it") }
// Person is called Anna
// Person is called Alex
// Person is called Brian
// Person is called Jack</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var names = new List<string> { "Anna", "Alex", "Brian", "Jack" };
foreach (var name in names)
{
Console.WriteLine($"Person is called {name}");
}
names.ForEach(name => Console.WriteLine($"Person is called {name}"));
// Person is called Anna
// Person is called Alex
// Person is called Brian
// Person is called Jack</code></pre></div></div></div><div class="case"><div class="name">Range Operator</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val names = arrayOf("Anna", "Alex", "Brian", "Jack")
val count = names.count()
for (i in 0..<count) {
println("Person ${i + 1} is called ${names[i]}")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var names = new[] { "Anna", "Alex", "Brian", "Jack" };
var count = names.Count();
foreach (var i in Enumerable.Range(0, count))
{
Console.WriteLine($"Person {i + 1} is called {names[i]}");
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
</code></pre></div></div></div><div class="case"><div class="name">Inclusive Range Operator</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>for (index in 1..5) {
println("$index times 5 is ${index * 5}")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>foreach (var index in Enumerable.Range(1, 5))
{
Console.WriteLine($"{index} times 5 is {index * 5}");
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
</code></pre></div></div></div><div class="case"><div class="name">Collection Range and Index</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val names = arrayOf("Anna", "Alex", "Brian", "Jill", "Jack")
val count = names.count()
for (name in names.slice(1..<count - 1)) {
println("Person is called $name")
}
// Person is called Alex
// Person is called Brian
// Person is called Jill</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var names = new[] { "Anna", "Alex", "Brian", "Jill", "Jack" };
foreach (var name in names[1..^1])
{
Console.WriteLine($"Person is called {name}");
}
// Person is called Alex
// Person is called Brian
// Person is called Jill
</code></pre></div></div></div></div><div class="section"><div class="title">COLLECTION OPERATIONS / LINQ</div><div class="case"><div class="name">Map</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val numbers = listOf(20, 19, 7, 12)
val multiplied = numbers.map { 3 * it }
// [ 60, 57, 21, 36 ]
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var numbers = new[] { 20, 19, 7, 12 };
var multiplied = numbers.Select(e => 3 * e);
// [ 60, 57, 21, 36 ]</code></pre></div></div></div><div class="case"><div class="name">Sort</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val ordered = listOf(1, 5, 3, 12, 2).sorted()
// [ 1, 2, 3, 5, 12 ]</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var ordered = new[] { 1, 5, 3, 12, 2 }.OrderBy(i => i);
// [ 1, 2, 3, 5, 12 ]</code></pre></div></div></div><div class="case"><div class="name">Filter / GroupBy / Average</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val datas = listOf(
SensorData(1, "A", 2.89),
SensorData(2, "B", 12.01),
SensorData(3, "B", 11.89),
SensorData(4, "A", 3.11),
SensorData(5, "A", -456.0)
)
val avgs = datas
.filter { it.value > -50.0 }
.groupBy(SensorData::location)
.map { Location(it.key, it.value.map(SensorData::value).average()) }
// (location=A, value=3.0)
// (location=B, value=11.95)</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var datas = new List<SensorData>
{
new SensorData { Id = 1, Location = "A", Value = 2.89 },
new SensorData { Id = 2, Location = "B", Value = 12.01 },
new SensorData { Id = 3, Location = "B", Value = 11.89 },
new SensorData { Id = 4, Location = "A", Value = 3.11 },
new SensorData { Id = 5, Location = "A", Value = -456.0 }
};
var avgs = datas
.Where(e => e.Value > -50.0)
.GroupBy(e => e.Location)
.Select(g => new {
Location = g.Key,
Value = g.Average(e => e.Value) });
// { Location = A, Value = 3.0 }
// { Location = B, Value = 11.95 }</code></pre></div></div></div><div class="case"><div class="name">Sequences</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Sequence is lazy
val seq = sequenceOf(1, 2, 3, 4)
.filter { println("Filter $it, "); it % 2 == 1 }
.map { println("Map $it, "); it * 2 }
// Computations are evaluated during terminal operation
val items = seq.toList()
// Filter 1,
// Map 1,
// Filter 2,
// Filter 3,
// Map 3,
// Filter 4,
// List is not lazy, so functions are evaluated immediately
val items2 = listOf(1, 2, 3, 4)
.filter { println("Filter $it, "); it % 2 == 1 }
.map { println("Map $it, "); it * 2 }
// Filter 1,
// Filter 2,
// Filter 3,
// Filter 4,
// Map 1,
// Map 3,</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// LINQ is lazy, so no need to use other collection types
var query = new List<int> { 1, 2, 3, 4 }
.Where(i =>
{
Console.WriteLine($"Filter {i}, ");
return i % 2 == 1;
}).Select(i =>
{
Console.WriteLine($"Map {i}, ");
return i * 2;
});
var items = query.ToList();
//Filter 1,
//Map 1,
//Filter 2,
//Filter 3,
//Map 3,
//Filter 4,</code></pre></div></div></div></div><div class="section"><div class="title">CLASSES</div><div class="case"><div class="name">Declaration</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>class Shape {
var numberOfSides = 0
fun simpleDescription() =
"A shape with $numberOfSides sides."
}
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>class Shape
{
public int NumberOfSides { get; set; }
public string SimpleDescription() =>
$"A shape with {NumberOfSides} sides.";
}
</code></pre></div></div></div><div class="case"><div class="name">Usage</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
// A shape with 7 sides.</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var shape = new Shape();
shape.NumberOfSides = 7;
var shapeDescription = shape.SimpleDescription();
// A shape with 7 sides.</code></pre></div></div></div><div class="case"><div class="name">Subclass</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>open class NamedShape(val name: String) {
var numberOfSides = 0
open fun simpleDescription() =
"A shape with $numberOfSides sides."
}
class Square(var sideLength: Double, name: String) :
NamedShape(name) {
init {
numberOfSides = 4
}
fun area() = sideLength.pow(2)
override fun simpleDescription() =
"A square with sides of length $sideLength."
}
val square = Square(5.2, "My square")
val area = square.area()
val desc = square.simpleDescription()
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>class NamedShape
{
private readonly string _name;
public NamedShape(string name) => _name = name;
protected int NumberOfSides { get; set; }
public virtual string SimpleDescription() =>
$"A shape with {NumberOfSides} sides.";
}
class Square: NamedShape
{
private readonly double _sideLength;
public Square(double sideLength, string name) : base(name)
{
_sideLength = sideLength;
NumberOfSides = 4;
}
public double Area() => Math.Pow(_sideLength, 2);
override public string SimpleDescription() =>
$"A square with sides of length {_sideLength}.";
}
var square = new Square(5.2, "My square");
var area = square.Area();
var desc = square.SimpleDescription();
</code></pre></div></div></div><div class="case"><div class="name">Data Class / Record</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>data class Customer(var id: Long, var name: String)
val customer = Customer(1, "Sachin")
val name = customer.name
customer.id = 2
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Pre C# 9 doesn't have data classes
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
var customer = new Customer { Id = 1, Name = "Sachin" };
var name = customer.Name;
customer.Id = 2
// C# 9 has records
// Records can be mutable, but they are primarily
// intended for supporting immutable data models
public record Customer
{
public int Id { get; set; }
public string Name { get; set; }
}</code></pre></div></div></div><div class="case"><div class="name">Immutable Data Class / Record</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>data class Customer(val id: Long, val name: String)
val customer = Customer(1, "Sachin")
val name = customer.name
customer.id = 2 // Error
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// C# 9 immutable records can be created with positional parameters
public record Customer(int Id, string Name);
Customer customer = new(1, "Sachin");
customer.Id = 2 // Error
// or with standard property syntax and init only setter
public record Customer
{
public int Id { get; init; }
public string Name { get; init; }
};
var customer = new Customer { Id = 1, Name = "Sachin" };
customer.Id = 2 // Error
// Pre C# 9
public class Customer
{
public Customer(int id, string name) => (Id, Name) = (id, name);
public int Id { get; }
public string Name { get; }
}
var customer = new Customer(1, "Sachin");
var name = customer.Name;
customer.Id = 2 // Error</code></pre></div></div></div><div class="case"><div class="name">Extensions / Extension Methods</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>fun MutableList<Int>.swap(idx1: Int, idx2: Int) {
val tmp = this[idx1]
this[idx1] = this[idx2]
this[idx2] = tmp
}
val list = mutableListOf(1, 5, 3)
list.swap(0, 2)
// [ 3, 5, 1 ]</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>public static class Extensions
{
public static void Swap(this List<int> list, int idx1, int idx2)
{
var temp = list[idx1];
list[idx1] = list[idx2];
list[idx2] = temp;
}
}
var list = new List<int> { 1, 5, 3 };
list.Swap(0, 2);
// [ 3, 5, 1 ]
</code></pre></div></div></div><div class="case"><div class="name">Interfaces</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>interface Nameable {
fun name(): String
}
fun <T: Nameable> genericFunction(x: T) {
println("Name is " + x.name())
}
class Person : Nameable {
override fun name() = "Person A"
}
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>interface INameable
{
string Name();
}
void GenericMethod<T>(T x) where T : INameable
{
Console.WriteLine("Name is " + x.Name());
}
class Person : INameable
{
public string Name() => "Person A";
}</code></pre></div></div></div></div><div class="section"><div class="title">TYPES</div><div class="case"><div class="name">Checking Type</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>var movieCount = 0
var songCount = 0
for (item in library) {
if (item is Movie) {
++movieCount
} else if (item is Song) {
++songCount
}
}
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var movieCount = 0;
var songCount = 0;
foreach (var item in library)
{
if (item is Movie)
++movieCount;
else if (item is Song)
++songCount;
}
</code></pre></div></div></div><div class="case"><div class="name">Casting</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Unsafe (throw exception)
val circle: Circle = shape as Circle
// Safe (return null)
val circle: Circle? = shape as Circle?
val circle: Circle? = shape as? Circle</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Unsafe (throw exception)
var circle = (Circle)shape;
// Safe (return null)
var circle = shape as Circle;
// If Nullable reference types enabled (optional feature)
Circle? circle = shape as Circle;</code></pre></div></div></div><div class="case"><div class="name">Smart Cast</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>for (current in library) {
if (current is Movie) {
println("Movie: '${current.name}', " +
"dir: ${current.director}")
}
}
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>foreach (var current in library)
{
if (current is Movie movie)
{
Console.WriteLine($"Movie: '{movie.Name}', " +
$"dir: {movie.Director}");
}
}
</code></pre></div></div></div></div><div class="section"><div class="title">EXCEPTIONS</div><div class="case"><div class="name">Exception Handling</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>try {
// some code
}
catch (e: SomeException) {
if (e.SomeCode == 404) {
// handle SomeException when SomeCode is 404
} else {
// handle SomeException
}
}
catch (e: Exception) {
// handle rest of the Exceptions
}
finally {
// optional finally block
}</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>try
{
// Some code
}
catch (SomeException e) when (e.SomeCode == 404)
{
// Handle SomeException only when SomeCode is 404
}
catch (SomeException e)
{
// Handle SomeException
}
catch (Exception e)
{
// Handle rest of the Exceptions
}
finally
{
// Optional finally block
}</code></pre></div></div></div><div class="case"><div class="name">Exception Expression</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// try is an expression, i.e., it may have a return value
val a: Int? = try { input.toInt() }
catch (e: NumberFormatException) { null }</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// try is not an expression
int? a;
try { a = int.Parse(input); }
catch { a = null; }</code></pre></div></div></div></div><div class="section"><div class="title">PATTERN MATCHING</div><div class="case"><div class="name">When / Switch Expression</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val nb = 42
val text = when (nb) {
in 0..7, 8, 9 -> "single digit"
10 -> "double digits"
in 11..99 -> "double digits"
in 100..999 -> "triple digits"
else -> "four or more digits"
}
// double digits</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Pre C# 9
var nb = 42;
var text = nb switch
{
int i when i < 10 => "single digit",
10 => "double digits",
int i when i < 100 => "double digits",
int i when i < 1000 => "triple digits",
_ => "four or more digits"
};
// With C# 9 relational and conjunctive patterns
var nb = 42;
var text = nb switch
{
< 10 => "single digit",
10 or (>= 11 and < 100) => "double digits",
< 1000 => "triple digits",
_ => "for or more digits",
};
// double digits</code></pre></div></div></div><div class="case"><div class="name">Is Expression / When Clause / Property Pattern</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Not supported yet
// https://youtrack.jetbrains.com/issue/KT-20004
// http://openjdk.java.net/jeps/305</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var result = item switch
{
Square s => Handle(s),
Circle { Radius: < 10 } c => HandleUnder10(c),
Circle { Radius: 20 } c => Handle20(c),
Circle c => Handle(c),
_ => throw new Exception("Unknown shape")
};
// Same with if statements
if (item is Square s)
{ }
else if (item is Circle { Radius: < 10 })
{ }
else if (item is Circle { Radius: 20 })
{ }
else if (item is Circle ci)
{ }</code></pre></div></div></div></div><div class="section"><div class="title">NULL</div><div class="case"><div class="name">Nullable Types</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>data class Measurement(val celsius: Double)
val data: Measurement = null // Error: can't be null
val data: Measurement? = null // Ok: can be null
fun printMayBeNull(data: Measurement?) {
// data can be null, must have null check
if (data == null)
return
println(data.celsius)
}
fun printNoNull(data: Measurement) {
// data can't be null. No need for check
println(data.celsius)
}
val current: Measurement? = getDataFromApi()
printMayBeNull(current) // Ok: can be null
if (current == null)
return
printNoNull(current)
</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Nullable reference types are optional feature in C#
public class Measurement
{
public double Celsius { get; set; }
}
Measurement? data = null; // Ok: can be null
Measurement data = null; // Error: can't be null
void PrintMayBeNull(Measurement? data)
{
// data can be null, must have null check
if (data == null)
return;
Console.WriteLine(data.Celsius);
}
void PrintNoNull(Measurement data)
{
// data can't be null. No need for check
Console.WriteLine(data.Celsius);
}
Measurement? current = GetDataFromApi();
PrintMayBeNull(current); // No need for check as method accepts nulls
if (current == null)
return;
PrintNoNull(current); // OK: Null is checked before method call</code></pre></div></div></div><div class="case"><div class="name">Null Conditional</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>data class DataPoint(val id: Int, val celsius: Double,
val child: DataPoint? = null)
val data = DataPoint(1, 22.1, DataPoint(2, 22.8))
val result = data.child?.child?.
let { toFahrenheit(it.celsius) } ?: Double.MIN_VALUE</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>public class DataPoint
{
public int Id { get; set; }
public double Celsius { get; set; }
public DataPoint? Child { get; set; }
}
var data = new DataPoint
{
Id = 1,
Celsius = 22.1,
Child = new DataPoint { Id = 2, Celsius = 22.8 }
};
var result = data.Child?.Child != null
? ToFahrenheit(data.Child.Child.Celsius)
: double.MinValue;</code></pre></div></div></div><div class="case"><div class="name">Elvis Operator / Null Coalescing</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>val data = DataPoint(1, 22.1, DataPoint(2, 22.8))
val result = data.child?.child?.celsius ?: Double.MIN_VALUE
// Double.MIN_VALUE</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var data = new DataPoint
{
Id = 1,
Celsius = 22.1,
Child = new DataPoint { Id = 2, Celsius = 22.8 }
};
var result = data.Child?.Child?.Celsius ?? double.MinValue;
// double.MinValue</code></pre></div></div></div><div class="case"><div class="name">Generics, Out and Conditional</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// Use .let and forget weird helper methods
val data = DataPoint(1, 22.1, DataPoint(2, 22.8))
val result = data.child?.child?.
let { toFahrenheit(it.celsius) } ?: Double.MIN_VALUE</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>// Generic helper method that will return boolean and set output
bool GetValue<T>(T input, out T output)
{
output = input;
return output != null;
}
var data = new DataPoint
{
Id = 1,
Celsius = 22.1,
Child = new DataPoint { Id = 2, Celsius = 22.8 }
};
var result = GetValue(data.Child?.Child, out var output)
? ToFahrenheit(output.Celsius)
: double.MinValue;
string set = "My text";
var text = GetValue(set, out var output) ? output : "Not set";
// "My text"
string notSet = null;
var text = GetValue(notSet, out var output) ? output : "Not set";
// "Not set"
</code></pre></div></div></div></div><div class="section"><div class="title">JSON / DYNAMIC</div><div class="case"><div class="name">Dynamic</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>// The dynamic type is not supported in code targeting the JVM
// https://kotlinlang.org/docs/reference/dynamic-type.html
// JSON example with data classes
data class Work(val name: String, val location: String)
data class User(val id: String, val work: Work)
val json = """[
{ "id": "A", "work": { "name": "ACME 2", "location": "NY" } },
{ "id": "B", "work": { "name": "Box Co", "location": "SF" } },
{ "id": "C", "work": { "name": "DotCom", "location": "NY" } }
]"""
val users = jacksonObjectMapper().readValue<List<User>>(json)
val name = users.first().work.name
// ACME 2
val fromNy = users
.filter { it.work.location == "NY" }
.map { it.id }
// [A, C]</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>/* with dynamic, type is not known until runtime */
var json = @"[
{ 'id': 'A', 'work': { 'name': 'ACME 2', 'location': 'NY' } },
{ 'id': 'B', 'work': { 'name': 'Box Co', 'location': 'SF' } },
{ 'id': 'C', 'work': { 'name': 'DotCom', 'location': 'NY' } }
]";
var users = JsonConvert.DeserializeObject<List<dynamic>>(json);
var name = users.First().work.name;
// ACME 2
var fromNY = users
.Where(e => e.work.location == "NY")
.Select(e => e.id);
// [A, C]</code></pre></div></div></div></div><div class="section"><div class="title">COROUTINES / TASKS</div><div class="case"><div class="name">Async / Await</div><div class="pair"><div class="card"><div class="lang">Kotlin</div><pre class="code"><code>data class Stats(val full_name: String, val stargazers_count: Int = -1, val forks: Int = -1)
val mapper = jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val repos = listOf("jetbrains/kotlin", "dotnet/csharplang")
val asyncRequests = repos.map { repo ->
GlobalScope.async {
val body = Fuel.get("https://api.github.com/repos/$repo")
.responseString()
.third.component1() // Fuel Result & Body
body?.let { mapper.readValue<Stats>(it) } ?: Stats(repo)
}
}
runBlocking {
val results = asyncRequests.map { it.await() }
results.forEach{ println("${it.full_name} : ${it.stargazers_count} - ${it.forks}") }
}</code></pre></div><div class="card"><div class="lang">C#</div><pre class="code"><code>var client = new HttpClient();
var repos = new [] { "jetbrains/kotlin", "dotnet/csharplang" };
var asyncRequests = repos.Select(async repo =>
{
var response = await client.GetAsync($"https://api.github.com/repos/{repo}");
var json = await response.Content.ReadAsStringAsync();
dynamic content = JsonConvert.DeserializeObject(json);
return new { repo, stars = content.stargazers_count, forks = content.forks };
});
var results = await Task.WhenAll(asyncRequests);
foreach(var data in results)
Console.WriteLine($"{data.repo} : {data.stars} - {data.forks}");</code></pre></div></div></div></div></body></html>