-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeed.xml
More file actions
2357 lines (1765 loc) · 264 KB
/
feed.xml
File metadata and controls
2357 lines (1765 loc) · 264 KB
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
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2024-07-31T20:05:38+00:00</updated><id>/feed.xml</id><title type="html">IQDevs</title><subtitle>Technology Excellence Redefined</subtitle><entry><title type="html">ZGPS - Achieving Abstraction with Golang</title><link href="/ZGPS-Achieving-Abstraction-with-Golang/" rel="alternate" type="text/html" title="ZGPS - Achieving Abstraction with Golang" /><published>2020-05-30T05:00:00+00:00</published><updated>2020-05-30T05:00:00+00:00</updated><id>/ZGPS%20-%20Achieving%20Abstraction%20with%20Golang</id><content type="html" xml:base="/ZGPS-Achieving-Abstraction-with-Golang/"><![CDATA[<p>One of the early design challenges we faced when designing the <code class="language-plaintext highlighter-rouge">DSP</code> (Device Service Provider) project is coming up with a plug-and-play architecture. <code class="language-plaintext highlighter-rouge">DSP</code>’s main responsibility is to read data from a specific tracking device, process and store the data, or send commands and process responses. Different devices come with different protocols, though they share common traits, like they all (all the ones we now support at least) are TCP based. Devices, when connected to <code class="language-plaintext highlighter-rouge">DSP</code>, are expected to be recognized so they’re handed to the proper protocol handler. Our silver bullet here is abstraction, but then we’re using Go, and Go doesn’t have native support for abstractions. So how do we solve this?</p>
<p>We came up with a list of functions every device –no matter how distinct– must support, and we created an interface called <code class="language-plaintext highlighter-rouge">DeviceProtocol</code> that encompasses all these functions. Our interface will include functions like <code class="language-plaintext highlighter-rouge">SetDeviceConnection</code>, <code class="language-plaintext highlighter-rouge">SetLogger</code>, <code class="language-plaintext highlighter-rouge">Read</code>, <code class="language-plaintext highlighter-rouge">Write</code>, <code class="language-plaintext highlighter-rouge">GetIMEI</code>, <code class="language-plaintext highlighter-rouge">SetUnit</code>, <code class="language-plaintext highlighter-rouge">Acknowledge</code>, <code class="language-plaintext highlighter-rouge">Reject</code>, <code class="language-plaintext highlighter-rouge">Handle</code>, <code class="language-plaintext highlighter-rouge">StoreRecord</code>, and <code class="language-plaintext highlighter-rouge">Disconnect</code>.</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c">// DeviceProtocol is a set of functions all supports protocols need to implement.</span>
<span class="k">type</span> <span class="n">DeviceProtocol</span> <span class="k">interface</span> <span class="p">{</span>
<span class="c">// SetDeviceConnection is called to hand the connection over to the device</span>
<span class="c">// protocol instance. This is the first thing that happens once a new</span>
<span class="c">// device is connected.</span>
<span class="n">SetDeviceConnection</span><span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">Conn</span><span class="p">)</span>
<span class="c">// SetLogger keeps a copy of a provided Logger for the protocol to consume.</span>
<span class="n">SetLogger</span><span class="p">(</span><span class="n">logger</span><span class="o">.</span><span class="n">Logger</span><span class="p">)</span>
<span class="c">// Read allows the protocol to read a specified number of bytes directly</span>
<span class="c">// from the device. Refer to the ReadParameters structure to find out</span>
<span class="c">// and/or alter the capabilities of the Read function.</span>
<span class="n">Read</span><span class="p">(</span><span class="n">ReadParameters</span><span class="p">)</span> <span class="p">(</span><span class="n">Buffer</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
<span class="c">// Write allows the protocol to send byte streams directly to the device.</span>
<span class="c">// If the number of bytes written does NOT comport with the number of bytes</span>
<span class="c">// in the slice passed to the function, an error is returned.</span>
<span class="n">Write</span><span class="p">([]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">error</span>
<span class="c">// GetIMEI does what is necessary for the protocol to retrieve the IMEI from</span>
<span class="c">// the device. Failures can be expected, and tend to be more occasional, then</span>
<span class="c">// they need to be, so the caller needs to always watch out for errors. That</span>
<span class="c">// is, if `error` is anything other than nil, the proper action is to reject</span>
<span class="c">// the connection and bailout.</span>
<span class="n">GetIMEI</span><span class="p">()</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
<span class="c">// Acknowledge is automatically called once an IMEI is retrieved and</span>
<span class="c">// authenticated.</span>
<span class="c">// NOTE: Units that are marked off as disabled in the database won't</span>
<span class="c">// be acknowledged.</span>
<span class="n">Acknowledge</span><span class="p">()</span> <span class="kt">error</span>
<span class="c">// Reject is automatically called if the device fails to send an IMEI</span>
<span class="c">// within a specified period of time, or if the IMEI is not found in</span>
<span class="c">// the database or if the database object is marked off as disabled.</span>
<span class="c">// This function is automatically called right before Disconnect is.</span>
<span class="n">Reject</span><span class="p">()</span> <span class="kt">error</span>
<span class="c">// SetUnit is called once a device is acknowledged. The point of this</span>
<span class="c">// call is to hand over the Unit object to the protocol so that the</span>
<span class="c">// protocol is capable of inferring the Unit identifier.</span>
<span class="n">SetUnit</span><span class="p">(</span><span class="n">ms</span><span class="o">.</span><span class="n">Unit</span><span class="p">)</span>
<span class="c">// Handle is the entry point to a device handler. Every supported protocol</span>
<span class="c">// needs to implement this function. <b>No abstraction version of this</span>
<span class="c">// function is provided</b> for the sole reason that different devices</span>
<span class="c">// come with different protocols.</span>
<span class="n">Handle</span><span class="p">()</span> <span class="kt">error</span>
<span class="c">// StoreRecord is responsible for processing one device Record at a time.</span>
<span class="c">// Record (defined in Record.go) is supposed to at least have a Unit</span>
<span class="c">// object (defined in ms/Unit.go) and a Position object (defined in</span>
<span class="c">// ms/Position.go). Whether the Position is valid or not is decided by</span>
<span class="c">// its own microservice later.</span>
<span class="n">StoreRecord</span><span class="p">(</span><span class="o">*</span><span class="n">Record</span><span class="p">)</span> <span class="kt">error</span>
<span class="c">// Disconnect is the last function called towards the end of the lifecycle</span>
<span class="c">// of a protocol instance. That is, the function is called before the</span>
<span class="c">// protocol instance is dismissed forever. Protocol lifecycle comes to an</span>
<span class="c">// end when the device has been idle (no data received from a device within a</span>
<span class="c">// designated timeframe), or if the device fails to send an IMEI or if the</span>
<span class="c">// device IMEI is not associated with any Unit objects in the database, or</span>
<span class="c">// if the Unit object is marked as disabled.</span>
<span class="n">Disconnect</span><span class="p">()</span> <span class="kt">error</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Soon after a tracking device connects, we call <code class="language-plaintext highlighter-rouge">SetDeviceConnection</code> with our connection object, we then call <code class="language-plaintext highlighter-rouge">GetIMEI</code> that’ll internally compose a device identifier request and send it to the device using the <code class="language-plaintext highlighter-rouge">Write</code> function. The response is then retrieved with the <code class="language-plaintext highlighter-rouge">Read</code> function. Our <code class="language-plaintext highlighter-rouge">GetIMEI</code> function returns either the device unique identifier or an error (happens when the client fails to provide its IMEI within a designated timeframe, or when invalid data is provided or when the function identifies a suspicious activity).</p>
<p>A lot of these functions will have identical internal implementations. For instance,</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">SetDeviceConnection</code>, <code class="language-plaintext highlighter-rouge">SetLogger</code> and <code class="language-plaintext highlighter-rouge">SetUnit</code> are a common one-liner across all protocol implementations.</li>
<li><code class="language-plaintext highlighter-rouge">Read</code> and <code class="language-plaintext highlighter-rouge">Write</code> will be identical across all protocols given Read is flexible with its <code class="language-plaintext highlighter-rouge">ReadParameters</code> and Write blindlessly transmits a given slice of bites. No device-specific intelligence required.</li>
<li><code class="language-plaintext highlighter-rouge">StoreRecord</code> is a device-agnostic microservice-consuming function that doesn’t need to be reimplemented for every protocol.</li>
<li><code class="language-plaintext highlighter-rouge">Disconnect</code> performs some Record-related actions (device-agnostic, remember?) and closes the TCP connection generically.</li>
</ul>
<p>The way around the issue is to have a form of abstraction that allows protocols to adopt at will and override when needed. Problem is Go isn’t an OOP language (that’s not to say OOP can’t be employed in the language), and so class abstraction isn’t a first-class construct of the language. What we do here is we create a <code class="language-plaintext highlighter-rouge">DeviceProtocolHeader</code> with our common functions defined and implemented, and aggregate the object in every protocol object we create:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c">// DeviceProtocolHeader has a set of abstract functions that device protocols tend to have</span>
<span class="c">// in common. Instead of having to re-implement the same errorprocedures for every</span>
<span class="c">// Protocol implementation, it is recommended to include this header and have</span>
<span class="c">// the extra functionality at no cost.</span>
<span class="k">type</span> <span class="n">DeviceProtocolHeader</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">logger</span><span class="o">.</span><span class="n">Logger</span>
<span class="n">client</span> <span class="n">net</span><span class="o">.</span><span class="n">Conn</span>
<span class="n">Unit</span> <span class="n">ms</span><span class="o">.</span><span class="n">Unit</span>
<span class="n">lastRecord</span> <span class="n">Record</span>
<span class="p">}</span>
<span class="c">// SetConnection ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">SetDeviceConnection</span><span class="p">(</span><span class="n">client</span> <span class="n">net</span><span class="o">.</span><span class="n">Conn</span><span class="p">)</span> <span class="p">{</span>
<span class="n">proto</span><span class="o">.</span><span class="n">client</span> <span class="o">=</span> <span class="n">client</span>
<span class="c">// Set timeout to however many seconds ReadTimeout has.</span>
<span class="n">readParams</span> <span class="o">:=</span> <span class="n">DefaultReadParameters</span><span class="p">()</span>
<span class="n">proto</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">SetReadDeadline</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">readParams</span><span class="o">.</span><span class="n">Timeout</span><span class="p">))</span>
<span class="p">}</span>
<span class="c">// SetLogger ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">SetLogger</span><span class="p">(</span><span class="n">logger</span> <span class="n">logger</span><span class="o">.</span><span class="n">Logger</span><span class="p">)</span> <span class="p">{</span>
<span class="n">proto</span><span class="o">.</span><span class="n">Logger</span> <span class="o">=</span> <span class="n">logger</span>
<span class="p">}</span>
<span class="c">// Read ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">Read</span><span class="p">(</span><span class="n">params</span> <span class="n">ReadParameters</span><span class="p">)</span> <span class="p">(</span><span class="n">Buffer</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buf</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="n">params</span><span class="o">.</span><span class="n">ByteCount</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><=</span> <span class="n">params</span><span class="o">.</span><span class="n">MaxTimeoutAttempts</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">bufLen</span><span class="p">,</span> <span class="n">_</span> <span class="o">:=</span> <span class="n">proto</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Read</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span> <span class="n">bufLen</span> <span class="o">></span> <span class="m">0</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">Buffer</span><span class="p">{</span><span class="n">buf</span><span class="p">[</span><span class="o">:</span><span class="n">bufLen</span><span class="p">]},</span> <span class="no">nil</span>
<span class="p">}</span>
<span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">Timeout</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">Buffer</span><span class="p">{},</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"Device read timeout"</span><span class="p">)</span>
<span class="p">}</span>
<span class="c">// Write ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">Write</span><span class="p">(</span><span class="n">data</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">bCount</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">proto</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Write</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">err</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="n">bCount</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"Failed to write some or all bytes. Expected count: %d, written count: %d"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">bCount</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
<span class="c">// SetUnit ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">SetUnit</span><span class="p">(</span><span class="n">unit</span> <span class="n">ms</span><span class="o">.</span><span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>
<span class="n">proto</span><span class="o">.</span><span class="n">Unit</span> <span class="o">=</span> <span class="n">unit</span>
<span class="p">}</span>
<span class="c">// StoreRecord ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">StoreRecord</span><span class="p">(</span><span class="n">record</span> <span class="o">*</span><span class="n">Record</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">record</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">errors</span><span class="o">.</span><span class="n">New</span><span class="p">(</span><span class="s">"Expected a Record. Received nil"</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">record</span><span class="o">.</span><span class="n">Unit</span> <span class="o">=</span> <span class="n">proto</span><span class="o">.</span><span class="n">Unit</span>
<span class="n">record</span><span class="o">.</span><span class="n">SetLogger</span><span class="p">(</span><span class="n">proto</span><span class="o">.</span><span class="n">Logger</span><span class="p">)</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">record</span><span class="o">.</span><span class="n">Store</span><span class="p">();</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">err</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">record</span><span class="o">.</span><span class="n">Position</span><span class="o">.</span><span class="n">Timestamp</span><span class="o">.</span><span class="n">After</span><span class="p">(</span><span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Position</span><span class="o">.</span><span class="n">Timestamp</span><span class="p">)</span> <span class="p">{</span>
<span class="c">// Prepare the last possible Record.</span>
<span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Flags</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="n">ms</span><span class="o">.</span><span class="n">Last</span><span class="p">)</span>
<span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Unit</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">Unit</span>
<span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Position</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">Position</span>
<span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Position</span><span class="o">.</span><span class="n">ID</span> <span class="o">=</span> <span class="m">0</span>
<span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Position</span><span class="o">.</span><span class="n">Speed</span> <span class="o">=</span> <span class="m">0</span>
<span class="c">// NOTE: Modifying the last Record can be done here.</span>
<span class="n">proto</span><span class="o">.</span><span class="n">Log</span><span class="p">(</span><span class="n">logger</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span> <span class="s">"Last known Position timestamp: %v"</span><span class="p">,</span> <span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Position</span><span class="o">.</span><span class="n">Timestamp</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
<span class="c">// Disconnect ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">DeviceProtocolHeader</span><span class="p">)</span> <span class="n">Disconnect</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
<span class="n">proto</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>
<span class="k">if</span> <span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="o">.</span><span class="n">Flags</span><span class="o">.</span><span class="n">Has</span><span class="p">(</span><span class="n">ms</span><span class="o">.</span><span class="n">Last</span><span class="p">)</span> <span class="p">{</span>
<span class="c">// Store last record. Whether this is a valid last trip or not</span>
<span class="c">// is left for upper layers to decide.</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">proto</span><span class="o">.</span><span class="n">StoreRecord</span><span class="p">(</span><span class="o">&</span><span class="n">proto</span><span class="o">.</span><span class="n">lastRecord</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="n">proto</span><span class="o">.</span><span class="n">Log</span><span class="p">(</span><span class="n">logger</span><span class="o">.</span><span class="n">ERROR</span><span class="p">,</span> <span class="s">"Error: %v"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
<span class="k">return</span> <span class="n">err</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So, when introducing a new protocol object (say a proprietary ZGPS protocol), we do the following</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">type</span> <span class="n">ZGPS</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">DeviceProtocolHeader</span>
<span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">ZGPS</span><span class="p">)</span> <span class="n">GetIMEI</span><span class="p">()</span> <span class="p">(</span><span class="kt">int64</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
<span class="c">// TODO: Here goes our proprietary IMEI retrieval implementation</span>
<span class="p">}</span>
<span class="c">// Acknowledge ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">ZGPS</span><span class="p">)</span> <span class="n">Acknowledge</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
<span class="c">// TODO: Here goes our proprietery device/request acknowledgment implementation</span>
<span class="p">}</span>
<span class="c">// Reject ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">ZGPS</span><span class="p">)</span> <span class="n">Reject</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
<span class="c">// TODO: Here goes our proprietery device/request rejection implementation</span>
<span class="p">}</span>
<span class="c">// Handle ...</span>
<span class="k">func</span> <span class="p">(</span><span class="n">proto</span> <span class="o">*</span><span class="n">ZGPS</span><span class="p">)</span> <span class="n">Handle</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
<span class="c">// TODO: Here goes our proprietary data/request processing implementation</span>
<span class="p">}</span>
</code></pre></div></div>
<p>What have we objectively achieved here?</p>
<ol>
<li>We’ve set ourselves up for a zero-duplication code base.</li>
<li>We’ve added the ability to introduce higher-level system-wide business logic (take <code class="language-plaintext highlighter-rouge">lastRecord</code> for example) that future SMEs don’t even have to know about, making it easier to specialize at their own space.</li>
<li>Bug hunting is now easier given the code is modularized yet cohesive, and fixes will often be made in one place.</li>
</ol>]]></content><author><name>Fadi Hanna Al-Kass</name></author><category term="Golang" /><summary type="html"><![CDATA[One of the early design challenges we faced when designing the DSP (Device Service Provider) project is coming up with a plug-and-play architecture. DSP’s main responsibility is to read data from a specific tracking device, process and store the data, or send commands and process responses. Different devices come with different protocols, though they share common traits, like they all (all the ones we now support at least) are TCP based. Devices, when connected to DSP, are expected to be recognized so they’re handed to the proper protocol handler. Our silver bullet here is abstraction, but then we’re using Go, and Go doesn’t have native support for abstractions. So how do we solve this?]]></summary></entry><entry><title type="html">Generic Types in Strongly Typed Languages</title><link href="/Generic-Types-in-Strongly-Typed-Languages/" rel="alternate" type="text/html" title="Generic Types in Strongly Typed Languages" /><published>2017-11-14T05:00:00+00:00</published><updated>2017-11-14T05:00:00+00:00</updated><id>/Generic%20Types%20in%20Strongly%20Typed%20Languages</id><content type="html" xml:base="/Generic-Types-in-Strongly-Typed-Languages/"><![CDATA[<p>Few days ago, I wrote <a href="https://github.com/alexcorvi/mongots">mongots</a>, an alternative API for <a href="https://www.mongodb.com/">MongoDB</a> to make it work better with <a href="https://www.typescriptlang.org/">TypeScript</a> (a strongly-typed language that compiles to JS) on the NodeJS environment.</p>
<p>“Alternative” is an overstatement, since it is totally built on top of the native MongoDB driver, and it’s not an ODM like <a href="http://mongoosejs.com/">Mongoose</a>, and it doesn’t provide any new functionality.</p>
<p>Then why did I write it? The answer is: “stronger types”. The native MongoDB driver has <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mongodb">its type definitions in the DefinitelyTyped repository</a>, can be easily installed, but I was annoyed by all the <code class="language-plaintext highlighter-rouge">any</code> keywords it was littered with. It’s not that the authors don’t know how to make it more strongly typed, it’s just that MongoDB native driver API has been designed in a way (for JavaScript) that makes strong typing almost impossible with some cases.</p>
<p>My journey in creating this library has given me an insight on how generic types can be so helpful in some cases, and after seeing some tweets criticizing TypeScript’s generic types, I’ve decided to write this post.</p>
<p>Throughout this post, I’ll use TypeScript as an example, because everyone with a JavaScript background can comprehend the code, and personally, it’s my language of choice.</p>
<h2 id="introduction-to-generic-types">Introduction to Generic Types</h2>
<p>Let’s start with an example, a common pattern for JavaScript developers is to copy JSON objects using <code class="language-plaintext highlighter-rouge">JSON.stringify</code> and <code class="language-plaintext highlighter-rouge">JSON.parse</code>, like this:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyObject</span> <span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">string</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">theCopy</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The parameter <code class="language-plaintext highlighter-rouge">obj</code> in the above example can be anything, it can be a number, a string, an array, object literal …etc. So adding type definitions might be quite useless (without generic types):</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyObject</span> <span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="kr">any</span><span class="p">):</span> <span class="kr">any</span> <span class="p">{</span>
<span class="kd">const</span> <span class="kr">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="kr">string</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">theCopy</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>But with generic types, our function becomes as strongly typed as any function can be:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyObject</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">T</span> <span class="p">{</span>
<span class="kd">const</span> <span class="kr">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="kr">string</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">theCopy</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">myObject</span> <span class="o">=</span> <span class="p">{</span> <span class="na">a</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">3</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nf">copyObject</span><span class="p">(</span><span class="nx">myObject</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">theCopy</span><span class="p">.</span><span class="nx">a</span><span class="p">);</span> <span class="c1">// OK!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">theCopy</span><span class="p">.</span><span class="nx">b</span><span class="p">);</span> <span class="c1">// OK!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">theCopy</span><span class="p">.</span><span class="nx">c</span><span class="p">);</span> <span class="c1">// Compile Error!</span>
</code></pre></div></div>
<p>The syntax for writing generic types is like many languages, before the parameters using the angle brackets.</p>
<p>Another example of how you can make use of generic types is when requesting data from a server.</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">getFromServer</span><span class="o"><</span><span class="nx">DataSchema</span><span class="o">></span><span class="p">(</span><span class="nx">url</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nx">Data</span> <span class="p">{</span>
<span class="c1">// make the request</span>
<span class="c1">// and return the data</span>
<span class="p">}</span>
<span class="kr">interface</span> <span class="nx">Employees</span> <span class="p">{</span>
<span class="nl">departmentA</span><span class="p">:</span> <span class="kr">string</span><span class="p">[];</span>
<span class="nl">departmentB</span><span class="p">:</span> <span class="kr">string</span><span class="p">[];</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">employees</span> <span class="o">=</span> <span class="nx">getFromServer</span><span class="o"><</span><span class="nx">Employees</span><span class="o">></span><span class="p">(</span><span class="dl">"</span><span class="s2">http://www.example.com/api/employees.json</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">employees</span><span class="p">.</span><span class="nx">departmentA</span><span class="p">);</span> <span class="c1">// OK!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">employees</span><span class="p">.</span><span class="nx">departmentB</span><span class="p">);</span> <span class="c1">// OK!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">employees</span><span class="p">.</span><span class="nx">departmentC</span><span class="p">);</span> <span class="c1">// Compile error!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">employees</span><span class="p">.</span><span class="nx">departmentA</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="c1">// OK!</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">employees</span><span class="p">.</span><span class="nx">departmentA</span> <span class="o">+</span> <span class="nx">employees</span><span class="p">.</span><span class="nx">departmentB</span><span class="p">);</span>
<span class="c1">// ^ Compile errors because they are arrays</span>
</code></pre></div></div>
<p>The previous example shows how generic types are treated like additional arguments in the function. And that’s what they really are, <em>additional arguments</em>. In the first example, however, TypeScript was smart enough to determine the type of the passed value, and we did not need to pass any generic type values in angle brackets. Typescript can also be smart and notify you when you do something like this:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyObject</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">T</span> <span class="p">{</span>
<span class="kd">const</span> <span class="kr">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="kr">string</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">theCopy</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">myObject</span> <span class="o">=</span> <span class="p">{</span> <span class="na">a</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">b</span><span class="p">:</span> <span class="mi">3</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">theCopy</span> <span class="o">=</span> <span class="nx">copyObject</span><span class="o"><</span><span class="kr">number</span><span class="o">></span><span class="p">(</span><span class="nx">myObject</span><span class="p">);</span>
<span class="c1">// ^ Compile Error:</span>
<span class="c1">// Argument of type '{ a: number; b: number; }'</span>
<span class="c1">// is not assignable to parameter of type 'number'.</span>
</code></pre></div></div>
<p>Now if you’re writing your server and your front end with typescript you don’t have to write the interface <code class="language-plaintext highlighter-rouge">Employees</code> twice, what you can do is structure your project in a way that the server (back-end) and the front-end share a directory where you keep type definitions.</p>
<p>So, in the types directory, you can have this file <code class="language-plaintext highlighter-rouge">interface.employee.ts</code></p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kr">interface</span> <span class="nx">Employee</span> <span class="p">{</span>
<span class="nl">name</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">birth</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In your server:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Employee</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../types/interface.employee.ts</span><span class="dl">"</span>
<span class="kd">const</span> <span class="nx">employeesCollection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">myDB</span><span class="p">.</span><span class="nx">collection</span><span class="o"><</span><span class="nx">Employee</span><span class="o">></span><span class="p">(</span><span class="dl">"</span><span class="s2">employees</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<p>And in your front end:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Employee</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">../types/interface.employee.ts</span><span class="dl">"</span>
<span class="kd">const</span> <span class="nx">employees</span> <span class="o">=</span> <span class="nx">getFromServer</span><span class="o"><</span><span class="nx">Employee</span><span class="o">></span><span class="p">(</span><span class="dl">"</span><span class="s2">http://www.example.com/api/employees/ahmed.json</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<p>And that barely scratches the surface of how powerful generic types can be.</p>
<h2 id="restricting-generic-types">Restricting Generic Types</h2>
<p>You can also restrict how generic your generic types can be, for example, let’s say that we have a function that logs the length of the passed value (whatever it is):</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">logLength</span> <span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">val</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>But there are only two built-in types in javascript that have the length property, <code class="language-plaintext highlighter-rouge">String</code> and <code class="language-plaintext highlighter-rouge">Array</code>. So what we can do is set a constraint on the generic type like this:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">hasLength</span> <span class="p">{</span>
<span class="nl">length</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nf">logLength</span> <span class="o"><</span><span class="nx">T</span> <span class="kd">extends</span> <span class="nx">hasLength</span><span class="o">></span> <span class="p">(</span><span class="nx">val</span><span class="p">:</span> <span class="nx">T</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">val</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">logLength</span><span class="p">(</span><span class="dl">"</span><span class="s2">string</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// OK</span>
<span class="nf">logLength</span><span class="p">([</span><span class="dl">"</span><span class="s2">a</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">b</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">c</span><span class="dl">"</span><span class="p">]);</span> <span class="c1">// OK</span>
<span class="nf">logLength</span><span class="p">({</span>
<span class="na">width</span><span class="p">:</span> <span class="mi">300</span><span class="p">,</span>
<span class="na">length</span><span class="p">:</span> <span class="mi">600</span>
<span class="p">});</span> <span class="c1">// Also OK because it has the length property</span>
<span class="nf">logLength</span><span class="p">(</span><span class="mi">17</span><span class="p">);</span> <span class="c1">// Compile Error!</span>
</code></pre></div></div>
<h2 id="index-types-with-generic-types">Index Types With Generic Types</h2>
<p>A more elaborate example is a function that copies (Using <code class="language-plaintext highlighter-rouge">JSON.stringify</code> and <code class="language-plaintext highlighter-rouge">JSON.parse</code>) a property of any object that it receives.</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyProperty</span><span class="o"><</span><span class="nx">OBJ</span><span class="p">,</span> <span class="nx">KEY</span> <span class="kd">extends</span> <span class="kr">keyof</span> <span class="nx">OBJ</span><span class="o">></span><span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="nx">OBJ</span><span class="p">,</span> <span class="nx">key</span><span class="p">:</span> <span class="nx">KEY</span><span class="p">):</span> <span class="nx">OBJ</span><span class="p">[</span><span class="nx">KEY</span><span class="p">]</span> <span class="p">{</span>
<span class="kd">const</span> <span class="kr">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]);</span>
<span class="kd">const</span> <span class="nx">copied</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="kr">string</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">copied</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">car</span> <span class="o">=</span> <span class="p">{</span> <span class="na">engine</span><span class="p">:</span> <span class="dl">"</span><span class="s2">v8</span><span class="dl">"</span><span class="p">,</span> <span class="na">milage</span><span class="p">:</span> <span class="mi">123000</span><span class="p">,</span> <span class="na">color</span><span class="p">:</span> <span class="dl">"</span><span class="s2">red</span><span class="dl">"</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">animal</span> <span class="o">=</span> <span class="p">{</span> <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Domestic Cat</span><span class="dl">"</span><span class="p">,</span> <span class="na">species</span><span class="p">:</span> <span class="dl">"</span><span class="s2">silvestris</span><span class="dl">"</span> <span class="p">};</span>
<span class="nf">copyProperty</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="dl">"</span><span class="s2">engine</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// OK</span>
<span class="nf">copyProperty</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="dl">"</span><span class="s2">color</span><span class="dl">"</span><span class="p">).</span><span class="nx">length</span><span class="p">;</span> <span class="c1">// OK</span>
<span class="nf">copyProperty</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="dl">"</span><span class="s2">milage</span><span class="dl">"</span><span class="p">).</span><span class="nx">length</span><span class="p">;</span> <span class="c1">// Compile error, because it's a number!</span>
<span class="nf">copyProperty</span><span class="p">(</span><span class="nx">animal</span><span class="p">,</span> <span class="dl">"</span><span class="s2">color</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// Compile error, because "color" is not a property on that object!</span>
<span class="c1">// so you can only pass the object's property names and</span>
<span class="c1">// typescript will be smart enough to determine their values</span>
</code></pre></div></div>
<p>Now let’s step it up a bit, by making our <code class="language-plaintext highlighter-rouge">copyProperty</code> able to copy multiple properties on the same call, so the second argument, will be an array of property names that will be copied and returned as an array.</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">copyProperties</span><span class="o"><</span><span class="nx">OBJ</span><span class="p">,</span> <span class="nx">KEY</span> <span class="kd">extends</span> <span class="kr">keyof</span> <span class="nx">OBJ</span><span class="o">></span><span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="nx">OBJ</span><span class="p">,</span> <span class="nx">keys</span><span class="p">:</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">KEY</span><span class="o">></span><span class="p">):</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">OBJ</span><span class="p">[</span><span class="nx">KEY</span><span class="p">]</span><span class="o">></span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">keys</span>
<span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">x</span> <span class="o">=></span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">x</span><span class="p">]))</span>
<span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">x</span> <span class="o">=></span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">x</span><span class="p">))</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">car</span> <span class="o">=</span> <span class="p">{</span> <span class="na">engine</span><span class="p">:</span> <span class="dl">"</span><span class="s2">v8</span><span class="dl">"</span><span class="p">,</span> <span class="na">milage</span><span class="p">:</span> <span class="mi">123000</span><span class="p">,</span> <span class="na">color</span><span class="p">:</span> <span class="dl">"</span><span class="s2">red</span><span class="dl">"</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">a</span><span class="p">:</span> <span class="kr">string</span><span class="p">[]</span> <span class="o">=</span> <span class="nf">copyProperties</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="p">[</span><span class="dl">"</span><span class="s2">engine</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">color</span><span class="dl">"</span><span class="p">]);</span> <span class="c1">// OK</span>
<span class="kd">const</span> <span class="nx">b</span><span class="p">:</span> <span class="kr">string</span><span class="p">[]</span> <span class="o">=</span> <span class="nf">copyProperties</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="p">[</span><span class="dl">"</span><span class="s2">engine</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">milage</span><span class="dl">"</span><span class="p">]);</span>
<span class="c1">// ^ Compile Error! because one of the array values is a number</span>
<span class="c1">// and that's because one of the properties</span>
<span class="c1">// we're copying is "milage".</span>
</code></pre></div></div>
<h2 id="mapped-generic-types">Mapped Generic Types</h2>
<p>Sometimes, we’d like to modify the values of the object while copying it. For example, we have this document object:</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nb">document</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">New Document</span><span class="dl">"</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">document content ...</span><span class="dl">"</span><span class="p">,</span>
<span class="na">createdAt</span><span class="p">:</span> <span class="mi">1510680155148</span>
<span class="p">};</span>
</code></pre></div></div>
<p>We’d like the copy to hold a different value for the <code class="language-plaintext highlighter-rouge">createdAt</code> property. So we’ll write a function that copies objects and takes a second argument that will be property names and values to be edited.</p>
<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c1">// this is a generic type, it takes any type (object)</span>
<span class="c1">// as an argument and returns the same type</span>
<span class="c1">// but with every property being optional</span>
<span class="kd">type</span> <span class="nb">Partial</span><span class="o"><</span><span class="nx">T</span><span class="o">></span> <span class="o">=</span> <span class="p">{</span>
<span class="p">[</span><span class="nx">P</span> <span class="k">in</span> <span class="kr">keyof</span> <span class="nx">T</span><span class="p">]?:</span> <span class="nx">T</span><span class="p">[</span><span class="nx">P</span><span class="p">]</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nf">copyAndModify</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">obj</span><span class="p">:</span> <span class="nx">T</span><span class="p">,</span> <span class="nx">mods</span><span class="p">:</span><span class="nb">Partial</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">):</span> <span class="nx">T</span> <span class="p">{</span>
<span class="kd">const</span> <span class="kr">string</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">copy</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="kr">string</span><span class="p">);</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">mods</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">key</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">copy</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">mods</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">copy</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">doc</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">New Document</span><span class="dl">"</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">document content ...</span><span class="dl">"</span><span class="p">,</span>
<span class="na">createdAt</span><span class="p">:</span> <span class="mi">1510680155148</span>
<span class="p">};</span>
<span class="nf">copyAndModify</span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="p">{</span> <span class="na">createdAt</span><span class="p">:</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">().</span><span class="nf">getTime</span><span class="p">()</span> <span class="p">})</span> <span class="c1">// OK</span>
<span class="nf">copyAndModify</span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">"</span><span class="s2">New title</span><span class="dl">"</span> <span class="p">})</span> <span class="c1">// OK</span>
<span class="nf">copyAndModify</span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="p">{</span> <span class="na">content</span><span class="p">:</span> <span class="mi">0</span> <span class="p">})</span>
<span class="c1">// Compile Error!</span>
<span class="c1">// Because content is a string, so we must</span>
<span class="c1">// put a string when modifying it</span>
<span class="nf">copyAndModify</span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="p">{</span> <span class="na">author</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Some one</span><span class="dl">"</span> <span class="p">})</span>
<span class="c1">// Compile Error!</span>
<span class="c1">// Because we did not have the property author on the original document</span>
</code></pre></div></div>
<p>So those were some of the ways that you can utilize generic types to write a more safe and expressive code.</p>
<p>Finally, I’d like to finish this post with one of my favorite quotes:</p>
<blockquote>
<p>Well engineered solutions fail early, fail fast, fail often.</p>
</blockquote>
<p>Happy coding!</p>]]></content><author><name>Alex Corvi</name></author><category term="TypeScript" /><summary type="html"><![CDATA[Few days ago, I wrote mongots, an alternative API for MongoDB to make it work better with TypeScript (a strongly-typed language that compiles to JS) on the NodeJS environment.]]></summary></entry><entry><title type="html">Constructors and Destructors in C</title><link href="/Constructors-and-Destructors-in-C/" rel="alternate" type="text/html" title="Constructors and Destructors in C" /><published>2017-10-25T05:00:00+00:00</published><updated>2017-10-25T05:00:00+00:00</updated><id>/Constructors%20and%20Destructors%20in%20C</id><content type="html" xml:base="/Constructors-and-Destructors-in-C/"><![CDATA[<blockquote>
<p>Everything discussed here is a feature brought to you by the <a href="https://gcc.gnu.org/"><code class="language-plaintext highlighter-rouge">GCC</code></a> compiler. If you happen to be using a different compiler, I’m not sure all or any of this would apply given the fact that these features aren’t part of the <code class="language-plaintext highlighter-rouge">C</code> programming language per se.</p>
</blockquote>
<p>When writing programs of considerable size and complexity, we tend to modularize our code. That is, we try to think of all different components as objects that can be easily moved around and fit within existing and future code. In C, it’s common practice for developers to divide code into libraries and header files that can be included as needed. When working with someone else’s library, you’d normally rather have a getting-started document that’s as short and as concise as possible.</p>
<p>Let’s consider an example. You’re working with a team that’s responsible for implementing a stack data structure and is expected to hand you the five essential functions every stack should have: <code class="language-plaintext highlighter-rouge">push()</code>, <code class="language-plaintext highlighter-rouge">pop()</code>, <code class="language-plaintext highlighter-rouge">peek()</code>, <code class="language-plaintext highlighter-rouge">isFull()</code>, and <code class="language-plaintext highlighter-rouge">isEmpty()</code>. You’re probably already wondering “who’s going to initialize the stack? Do I have to? Will they hand me an initialized instance? Is it stack-allocated or heap-allocated? If it’s heap-allocated, do I have to worry about freeing it myself?” The stream of questions can literally be endless the more complex the library is. Wouldn’t it be better for the library to handle all the heavy lifting of having to instantiate all necessary data objects and do the housekeeping after itself when its job is finished (something of the nature of a constructor that’s called automatically once the library is included and a destructor that’s called when the library is done with)?</p>
<h2 id="constructors">Constructors</h2>
<p>Let’s assume we have a header file named ‘stack.h’:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#ifndef STACK_H
#define STACK_H
</span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="c1"> // printf</span><span class="cp">
#include</span> <span class="cpf"><stdlib.h></span><span class="c1"> // calloc & free</span><span class="cp">
#include</span> <span class="cpf"><stdbool.h></span><span class="c1"> // true & false</span><span class="cp">
</span>
<span class="cp">#define STACK_CAP 12
</span>
<span class="kt">int</span><span class="o">*</span> <span class="n">stack</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">stack_ptr</span><span class="p">;</span>
<span class="n">bool</span> <span class="nf">isEmpty</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">stack_ptr</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">bool</span> <span class="nf">isFull</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">stack_ptr</span> <span class="o">==</span> <span class="n">STACK_CAP</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">bool</span> <span class="nf">push</span><span class="p">(</span><span class="kt">int</span> <span class="n">val</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">isFull</span><span class="p">())</span> <span class="p">{</span>
<span class="n">stack</span><span class="p">[</span><span class="n">stack_ptr</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">bool</span> <span class="nf">peek</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">ref</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">isEmpty</span><span class="p">())</span> <span class="p">{</span>
<span class="o">*</span><span class="n">ref</span> <span class="o">=</span> <span class="n">stack</span><span class="p">[</span><span class="n">stack_ptr</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">bool</span> <span class="nf">pop</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">ref</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">peek</span><span class="p">(</span><span class="n">ref</span><span class="p">))</span> <span class="p">{</span>
<span class="n">stack_ptr</span><span class="o">--</span><span class="p">;</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif
</span></code></pre></div></div>
<p>You’ve probably already noticed that <code class="language-plaintext highlighter-rouge">stack</code> and <code class="language-plaintext highlighter-rouge">stack_ptr</code> are left uninitialized, so if you were to blindly use <code class="language-plaintext highlighter-rouge">push</code>, <code class="language-plaintext highlighter-rouge">peek</code>, or <code class="language-plaintext highlighter-rouge">pop</code>, you’re going to run into a segmentation fault as <code class="language-plaintext highlighter-rouge">stack</code> is a <code class="language-plaintext highlighter-rouge">NULL</code> pointer, and <code class="language-plaintext highlighter-rouge">stack_ptr</code> is likely to contain some gibberish that was left behind on the stack. The proper way to use these functions would be to allocate memory for the <code class="language-plaintext highlighter-rouge">stack</code> pointer and <code class="language-plaintext highlighter-rouge">free</code> it when you’re done. An even better way to do this would be to have this task automatically preformed at the time of including this header file. This is done through a library constructor, and it’s done as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Library Constructor
@Brief: This function is automatically called when
the containing header file is included.
*/</span>
<span class="n">__attribute__</span><span class="p">((</span><span class="n">constructor</span><span class="p">))</span> <span class="kt">void</span> <span class="nf">start</span><span class="p">()</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Inside Constructor</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">stack_ptr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">stack</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="n">calloc</span><span class="p">(</span><span class="n">STACK_CAP</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The function above needs to be located inside your header file and will be automatically called once you’ve included the header file somewhere in your code.</p>
<blockquote>
<p>In case you didn’t know, <code class="language-plaintext highlighter-rouge">#ifndef STACK_H</code>, <code class="language-plaintext highlighter-rouge">#define STACK_H</code> and <code class="language-plaintext highlighter-rouge">#endif</code> are needed to prevent multiple or recursive includes that’ll cause the compiler to run into redefinition issues.</p>
</blockquote>
<p>Now the following program:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp">
#include</span> <span class="cpf">"header.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Inside main</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Will generate the following output:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Inside Constructor
Inside Main
</code></pre></div></div>
<p>And exit peacefully… Well not really peacefully. At least not in every sense of the word as your program has left some heap-allocated memory un-deallocated. You’re not likely going to see your program crash or anything, but you’ve still introduced a bug to your system that the OS may or may not be able to resolve depending on what OS you happen to be using. The proper way to go about programmatically solve this problem is to use a destructor in your application. A destructor is another function that gets called automatically once you’re done with the library. Read ahead to find out how this is done.</p>
<h2 id="destructors">Destructors</h2>
<p>You’re going to like this part.</p>
<p>We’ve used <code class="language-plaintext highlighter-rouge">__attribute__((constructor))</code> to introduce a constructor into our code, so you’re probably already thinking a <code class="language-plaintext highlighter-rouge">__attribute__((destructor))</code> is what we’d use to add a destructor, in which case you’d be absolutely right. Here’s our destructor function implementation for our stack library:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Library Destructor
@Brief: This function is automatically called when
the containing header file is dismissed (normally
at the end of the program lifecycle).
*/</span>
<span class="n">__attribute__</span><span class="p">((</span><span class="n">destructor</span><span class="p">))</span> <span class="kt">void</span> <span class="nf">finish</span><span class="p">()</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Inside Destructor</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">stack</span><span class="p">);</span>
<span class="n">stack</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now if you execute the same tiny program we’ve written above, you’ll get the following output:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Inside Constructor
Inside Main
Inside Destructor
</code></pre></div></div>
<p>And there we’ve achieved a library implementation that takes care of all necessary memory management for us.</p>]]></content><author><name>Fadi Hanna Al-Kass</name></author><category term="C" /><summary type="html"><![CDATA[Everything discussed here is a feature brought to you by the GCC compiler. If you happen to be using a different compiler, I’m not sure all or any of this would apply given the fact that these features aren’t part of the C programming language per se.]]></summary></entry><entry><title type="html">Remote Procedure Calls in C</title><link href="/Remote-Procedure-Calls-in-C/" rel="alternate" type="text/html" title="Remote Procedure Calls in C" /><published>2017-10-22T05:00:00+00:00</published><updated>2017-10-22T05:00:00+00:00</updated><id>/Remote%20Procedure%20Calls%20in%20C</id><content type="html" xml:base="/Remote-Procedure-Calls-in-C/"><![CDATA[<p>I have recently put together a quick Remote Procedure Call (RPC) demo in C and checked it into <a href="https://github.com/Alkass/cRPC">my Github account</a>, then I realized I still have a couple of minutes left on my hands, so I decided to write a walk-through blog post.</p>
<p>Remote Procedure Calls, if you’re not familiar with them, are library implementations that allow you to remotely host some code (normally in the form of classes and functions) and invoke those classes and functions as needed.</p>
<p>Why would you ever want to do that? I mean, what benefit do you get from having pieces of your code run on a remote server? There actually are a number of valid reasons why that would be the case, but I’m only interested in addressing two as I don’t want to run off topic. One reason is performance. Say a mobile app you’ve been writing requires high processing power availability to compute some complex mathematical equations. Most mobile devices aren’t meant to be cutting-edge processing devices that are able to scale up to any task you hand to them. In a case like this, you’d probably better off hand the calculation task to a more processing-ready device and ask for the results since that’s all you’re really interested in. Another reason is security. If you’re developing a banking solution, for instance, chances are you want to make it as hard as possible for reverse engineers to hack into your code and find out how deposits, withdraws, and transactions are made. RPCs are a viable option here.</p>
<p>Now onto some technical stuff…</p>
<p>If you’ve ever written TCP-based projects in your life, chances are you’ve serialized data at one end and deserialized it at the other end. Serialization often takes the form of a string that is supposedly safe to parse. If you’re a performance rat like myself, you’re probably seeing a problem already. String parsing is expensive and error prone. Having to parse a string on the fly means more code, more code (in most cases) means (1) slower code and (2) more possible bugs. More bugs means more time on debugging and less on productivity. You see where I’m going with this.</p>
<p>What I’d suggest as a better alternative is communicating through a stream of bytes that conform to a set of standards.</p>
<p>Say you’re building a remote controlled calculator with the most four basic operations (addition, subtraction, multiplication, and division). Now to be honest, I don’t know why you’d ever want to build this calculator. That’d be stupid. But for the sake of clarity, I couldn’t have thought of an easier example.</p>
<p>To properly send a request to your server, you’ll need to have an agreement on a request standard. Our request standard can be implemented as a <code class="language-plaintext highlighter-rouge">C</code> <code class="language-plaintext highlighter-rouge">struct</code> with a pre-determined number of bytes. All requests sent to the server must be fit within this number of byte count so the server will always know how many bytes to read at a time that make up a single request.</p>
<p>Before we implement our <code class="language-plaintext highlighter-rouge">Request</code> <code class="language-plaintext highlighter-rouge">struct</code>, let’s first decide what fields we need to include.</p>
<p>What we could do is always start with a conventional acknowledgment byte that helps both the server and the client decide whether the number of bytes read make up a valid request/response to be processed. This is extremely useful when debugging cases when one side of your project starts to misbehave, then you could do some debugging and make sure outgoing requests or incoming responses are valid by checking against the acknowledgment byte. We shall call this field <code class="language-plaintext highlighter-rouge">ack</code> for ease of writing.</p>
<p>Another useful field we could include is a request identifier. Identifiers are useful in cases when the client isn’t reading the responses right away and may have difficulty telling the responses apart. What we could do here is include the identifier as part of the response we send back as a server.</p>
<p>Our third field will be the operation field. This field tells us what function the user wants to execute.</p>
<p>We’ll also need two fields for the parameters.</p>
<p>Sounds about it!</p>
<p>Now, 1 field for <code class="language-plaintext highlighter-rouge">ack</code>, 1 for <code class="language-plaintext highlighter-rouge">id</code>, 1 for <code class="language-plaintext highlighter-rouge">op</code> and 2 for <code class="language-plaintext highlighter-rouge">params</code> add up to 5 bytes. Every time the server attempts to read a request, it’ll read exactly 5 bytes.</p>
<p>Our <code class="language-plaintext highlighter-rouge">strcut</code> will look like so:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="kt">char</span> <span class="n">ack</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">id</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">op</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">params</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span> <span class="n">Request</span><span class="p">;</span>
</code></pre></div></div>
<p>Characters in <code class="language-plaintext highlighter-rouge">C</code> are 1 byte (8-bit) integers. because <code class="language-plaintext highlighter-rouge">byte</code> isn’t a valid data type in <code class="language-plaintext highlighter-rouge">C</code>, we can type-define it as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">char</span> <span class="n">byte</span><span class="p">;</span>
</code></pre></div></div>
<p>and use it as so:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">byte</span> <span class="n">ack</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">id</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">op</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">params</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span> <span class="n">Request</span><span class="p">;</span>
</code></pre></div></div>
<p>Our acknowledgment byte is consensual between the server and the client. We’ll make it 10 and set it as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define ACK 0xA
</span></code></pre></div></div>
<p>Our operations can be part of an <code class="language-plaintext highlighter-rouge">OpType</code> <code class="language-plaintext highlighter-rouge">enum</code> as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
<span class="n">ADD</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">SUB</span><span class="p">,</span>
<span class="n">MUL</span><span class="p">,</span>
<span class="n">DIV</span>
<span class="p">}</span> <span class="n">OpType</span><span class="p">;</span>
</code></pre></div></div>
<p>Which allows us to replace the <code class="language-plaintext highlighter-rouge">byte</code> type in our <code class="language-plaintext highlighter-rouge">Request</code> <code class="language-plaintext highlighter-rouge">struct</code> with <code class="language-plaintext highlighter-rouge">OpType</code>, except we’ll run into a problem that is <code class="language-plaintext highlighter-rouge">enums</code> in <code class="language-plaintext highlighter-rouge">C</code> are of type integer (4-bytes long), but this issue can be overcome by enabling the <code class="language-plaintext highlighter-rouge">-fshort-enums</code> <code class="language-plaintext highlighter-rouge">GCC</code> switch that reduces the size of enums to 1 byte. Now we can re-write our <code class="language-plaintext highlighter-rouge">Request</code> <code class="language-plaintext highlighter-rouge">struct</code> as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">byte</span> <span class="n">ack</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">id</span><span class="p">;</span>
<span class="n">OpType</span> <span class="n">op</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">params</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span> <span class="n">Request</span><span class="p">;</span>
</code></pre></div></div>
<p>Now let’s define our <code class="language-plaintext highlighter-rouge">Response</code> <code class="language-plaintext highlighter-rouge">struct</code>.</p>
<p>We’ll need a starting acknowledgment byte, so that’s one.</p>
<p>We’ll also need to include the request identifier. That’s two.</p>
<p>Not every request sent to the server is a valid request. The user may be requesting a functionality that has not been yet implemented or does not exist. For this, we could include a status field that helps the client decide whether the request was handled successfully.</p>
<p>If the request is handled successfully, we’ll need to return some data to the user. We’ll need a data field to contain the result.</p>
<p>That adds up to four bytes. Here’s what our <code class="language-plaintext highlighter-rouge">Response</code> object will look like:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">byte</span> <span class="n">ack</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">id</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">status</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Response</span><span class="p">;</span>
</code></pre></div></div>
<p>Now assume you have a server up and running waiting to process some requests. You’d declare a <code class="language-plaintext highlighter-rouge">Request</code> object and <code class="language-plaintext highlighter-rouge">Response</code> object as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Request</span> <span class="n">req</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="n">Response</span> <span class="n">res</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
</code></pre></div></div>
<blockquote>
<p>The <code class="language-plaintext highlighter-rouge">{0}</code> is syntactic sugar that tells the compiler to set all values within the structure to zero.</p>
</blockquote>
<p>You’d then be reading the request as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">read</span><span class="p">(</span><span class="n">comm_fd</span><span class="p">,</span> <span class="p">(</span><span class="n">byte</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">req</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Request</span><span class="p">));</span>
</code></pre></div></div>
<blockquote>
<p>The <code class="language-plaintext highlighter-rouge">(byte*)&req</code> typecasts our <code class="language-plaintext highlighter-rouge">Request</code> struct into a byte pointer.</p>
</blockquote>
<p>After a so number of bytes (5 in our case) has been read and converted to a <code class="language-plaintext highlighter-rouge">Request</code> object, we can go ahead and verify that the request is valid by checking against our consensual acknowledgment byte as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">req</span><span class="p">.</span><span class="n">ack</span> <span class="o">==</span> <span class="n">ACK</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Request is successful. Move forward</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The first thing we could do is prepare the <code class="language-plaintext highlighter-rouge">ack</code> and <code class="language-plaintext highlighter-rouge">id</code> fields in our Response object as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">res</span><span class="p">.</span><span class="n">ack</span> <span class="o">=</span> <span class="n">req</span><span class="p">.</span><span class="n">ack</span><span class="p">;</span>
<span class="n">res</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">req</span><span class="p">.</span><span class="n">id</span><span class="p">;</span>
</code></pre></div></div>
<p>Then call a <code class="language-plaintext highlighter-rouge">handleRequest</code> function that’s responsible for handling the request and handing back the data. This function (and its callees) are implemented as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">handleAdd</span><span class="p">(</span><span class="k">const</span> <span class="n">Request</span><span class="o">*</span> <span class="n">req</span><span class="p">,</span> <span class="n">Response</span><span class="o">*</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"res->data = %d + %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="n">res</span><span class="o">-></span><span class="n">data</span> <span class="o">=</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">handleSub</span><span class="p">(</span><span class="k">const</span> <span class="n">Request</span><span class="o">*</span> <span class="n">req</span><span class="p">,</span> <span class="n">Response</span><span class="o">*</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"res->data = %d - %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="n">res</span><span class="o">-></span><span class="n">data</span> <span class="o">=</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">handleMul</span><span class="p">(</span><span class="k">const</span> <span class="n">Request</span><span class="o">*</span> <span class="n">req</span><span class="p">,</span> <span class="n">Response</span><span class="o">*</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"res->data = %d * %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="n">res</span><span class="o">-></span><span class="n">data</span> <span class="o">=</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">handleDiv</span><span class="p">(</span><span class="k">const</span> <span class="n">Request</span><span class="o">*</span> <span class="n">req</span><span class="p">,</span> <span class="n">Response</span><span class="o">*</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"res->data = %d / %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="n">res</span><span class="o">-></span><span class="n">data</span> <span class="o">=</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="n">req</span><span class="o">-></span><span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">handleRequest</span><span class="p">(</span><span class="k">const</span> <span class="n">Request</span><span class="o">*</span> <span class="n">req</span><span class="p">,</span> <span class="n">Response</span><span class="o">*</span> <span class="n">res</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">req</span><span class="o">-></span><span class="n">op</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">ADD</span><span class="p">:</span>
<span class="k">return</span> <span class="n">handleAdd</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span>
<span class="k">case</span> <span class="n">SUB</span><span class="p">:</span>
<span class="k">return</span> <span class="n">handleSub</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span>
<span class="k">case</span> <span class="n">MUL</span><span class="p">:</span>
<span class="k">return</span> <span class="n">handleMul</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span>
<span class="k">case</span> <span class="n">DIV</span><span class="p">:</span>
<span class="k">return</span> <span class="n">handleDiv</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span>
<span class="nl">default:</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And can be called as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">handleRequest</span><span class="p">(</span><span class="o">&</span><span class="n">req</span><span class="p">,</span> <span class="o">&</span><span class="n">res</span><span class="p">))</span> <span class="p">{</span>
<span class="n">res</span><span class="p">.</span><span class="n">status</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">res</span><span class="p">.</span><span class="n">status</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The response can be sent to the client as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">write</span><span class="p">(</span><span class="n">comm_fd</span><span class="p">,</span> <span class="p">(</span><span class="n">byte</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">res</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Response</span><span class="p">));</span>
</code></pre></div></div>
<p>And there we have a fully functional RPC server implementation capable of performing just about anything when expanded.</p>
<blockquote>
<p>The demo I referred to at the beginning of this post can be found <a href="https://github.com/Alkass/cRPC">here</a></p>
</blockquote>]]></content><author><name>Fadi Hanna Al-Kass</name></author><category term="C" /><summary type="html"><![CDATA[I have recently put together a quick Remote Procedure Call (RPC) demo in C and checked it into my Github account, then I realized I still have a couple of minutes left on my hands, so I decided to write a walk-through blog post.]]></summary></entry><entry><title type="html">Crafting Code - Building Common Interfaces</title><link href="/Crafting-Code-1/" rel="alternate" type="text/html" title="Crafting Code - Building Common Interfaces" /><published>2017-06-20T05:00:00+00:00</published><updated>2017-06-20T05:00:00+00:00</updated><id>/Crafting%20Code%201</id><content type="html" xml:base="/Crafting-Code-1/"><![CDATA[<p>When writing libraries, APIs, and SDKs, the less stuff you ask your user to memorize the better it looks to you and feels to them. For instance, if you were to write a Math library that performs some arithmetic operations, you could write your library functions as so:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="n">op1</span> <span class="o">+</span> <span class="n">op2</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">sub</span><span class="p">(</span><span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="n">op1</span> <span class="o">-</span> <span class="n">op2</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">mul</span><span class="p">(</span><span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="n">op1</span> <span class="o">*</span> <span class="n">op2</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">div</span><span class="p">(</span><span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="n">op1</span> <span class="o">/</span> <span class="n">op2</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And that’ll require the user to import his/her desired function or set of functions as needed. This is fine, but wouldn’t it be better if you could provide only one function that does all these operations? We’re going to call this function a common interface, but this procedure is called a passthrough in the professional field. A passthrough function is a multi-purpose entry point to a set of different classes or functions. In the case of our Math library, we could have our passthrough function written as follows:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">passthrough</span><span class="p">(</span><span class="n">operation</span><span class="p">:</span> <span class="o">&</span><span class="k">'static</span> <span class="nb">str</span><span class="p">,</span> <span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">match</span> <span class="n">operation</span> <span class="p">{</span>
<span class="s">"+"</span> <span class="k">=></span> <span class="nf">add</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="s">"-"</span> <span class="k">=></span> <span class="nf">sub</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="s">"*"</span> <span class="k">=></span> <span class="nf">mul</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="s">"/"</span> <span class="k">=></span> <span class="nf">div</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="n">_</span> <span class="k">=></span> <span class="mi">0</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">,</span> <span class="c1">//Return 0 if unknown operation. Near future bug alert!!!</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That allows us to do something like this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">passthrough</span><span class="p">(</span><span class="s">"+"</span><span class="p">,</span> <span class="mi">10</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">,</span> <span class="mf">12.3</span><span class="p">);</span>
</code></pre></div></div>
<p>Instead of this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">add</span><span class="p">(</span><span class="mf">32.4</span><span class="p">,</span> <span class="mi">12</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">);</span>
</code></pre></div></div>
<p>But there’s more we could do here. So, for instance, instead of specifying the operation as a string and expose our code to all sorts of correctness bugs (afterall, our <code class="language-plaintext highlighter-rouge">passthrough()</code> function won’t warn us about an invalid operation), we could do something like this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">OperationType</span> <span class="p">{</span>
<span class="n">ADD</span><span class="p">,</span>
<span class="n">SUB</span><span class="p">,</span>
<span class="n">MUL</span><span class="p">,</span>
<span class="n">DIV</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">passthrough</span><span class="p">(</span><span class="n">operation</span><span class="p">:</span> <span class="n">OperationType</span><span class="p">,</span> <span class="n">op1</span><span class="p">:</span> <span class="nb">f32</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">match</span> <span class="n">operation</span> <span class="p">{</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">ADD</span> <span class="k">=></span> <span class="nf">add</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">SUB</span> <span class="k">=></span> <span class="nf">sub</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">MUL</span> <span class="k">=></span> <span class="nf">mul</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">DIV</span> <span class="k">=></span> <span class="nf">div</span><span class="p">(</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">),</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That will at least force the user to select one of many options, and anything that’s not on the list won’t slide. But that’s not all either. There’s still more that can be done to tweak our code.</p>
<p>Notice how <code class="language-plaintext highlighter-rouge">passthrough</code> will always take two operands, no more or less parameters. What if, in the future, you decide to add an operation that requires only one operand (a square root function for example). You may be able to get away with something as easy as <code class="language-plaintext highlighter-rouge">passthrough(OperationType::SQRT, 25, 0)</code>, but that neither looks clean nor is something a team of professional developers would approve of. Perhaps we could turn our operands into a flexible object, and for the sake of simplicity we shall call our object <code class="language-plaintext highlighter-rouge">Request</code> and have it implemented as follows:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">Request</span> <span class="p">{</span>
<span class="n">NoOps</span><span class="p">,</span>
<span class="nf">OneOp</span><span class="p">(</span><span class="nb">f32</span><span class="p">),</span>
<span class="nf">TwoOps</span><span class="p">(</span><span class="nb">f32</span><span class="p">,</span> <span class="nb">f32</span><span class="p">),</span>
<span class="nf">ThreeOps</span><span class="p">(</span><span class="nb">f32</span><span class="p">,</span> <span class="nb">f32</span><span class="p">,</span> <span class="nb">f32</span><span class="p">),</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And re-implement our <code class="language-plaintext highlighter-rouge">passthrough()</code> function to work with a <code class="language-plaintext highlighter-rouge">Request</code> object as follows:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">passthrough</span><span class="p">(</span><span class="n">operation</span><span class="p">:</span> <span class="n">OperationType</span><span class="p">,</span> <span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">match</span> <span class="n">operation</span> <span class="p">{</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">ADD</span> <span class="k">=></span> <span class="nf">add</span><span class="p">(</span><span class="n">req</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">SUB</span> <span class="k">=></span> <span class="nf">sub</span><span class="p">(</span><span class="n">req</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">MUL</span> <span class="k">=></span> <span class="nf">mul</span><span class="p">(</span><span class="n">req</span><span class="p">),</span>
<span class="nn">OperationType</span><span class="p">::</span><span class="n">DIV</span> <span class="k">=></span> <span class="nf">div</span><span class="p">(</span><span class="n">req</span><span class="p">),</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And re-implement our arithmetic functions to use our <code class="language-plaintext highlighter-rouge">Request</code> object instead of straight operands:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="n">req</span><span class="p">:</span> <span class="n">Request</span><span class="p">)</span> <span class="k">-></span> <span class="nb">f32</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">match</span> <span class="n">req</span> <span class="p">{</span>
<span class="nn">Request</span><span class="p">::</span><span class="n">NoOps</span> <span class="k">=></span> <span class="mi">0</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">,</span>
<span class="nn">Request</span><span class="p">::</span><span class="nf">OneOp</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="k">=></span> <span class="n">a</span><span class="p">,</span><span class="n">w</span>
<span class="nn">Request</span><span class="p">::</span><span class="nf">TwoOps</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="k">=></span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">,</span>
<span class="nn">Request</span><span class="p">::</span><span class="nf">ThreeOps</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="k">=></span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="n">c</span><span class="p">,</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And the resulting code will then allow us to do something like this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">passthrough</span><span class="p">(</span><span class="nn">OperationType</span><span class="p">::</span><span class="n">ADD</span><span class="p">,</span> <span class="nn">Request</span><span class="p">::</span><span class="n">NoOps</span><span class="p">);</span>
</code></pre></div></div>
<p>Or this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">passthrough</span><span class="p">(</span><span class="nn">OperationType</span><span class="p">::</span><span class="n">ADD</span><span class="p">,</span> <span class="nn">Request</span><span class="p">::</span><span class="nf">TwoOps</span><span class="p">(</span><span class="mf">10.1</span><span class="p">,</span> <span class="mf">40.5</span><span class="p">));</span>
</code></pre></div></div>
<p>Or this:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">passthrough</span><span class="p">(</span><span class="nn">OperationType</span><span class="p">::</span><span class="n">ADD</span><span class="p">,</span> <span class="nn">Request</span><span class="p">::</span><span class="nf">ThreeOps</span><span class="p">(</span><span class="mf">10.1</span><span class="p">,</span> <span class="mf">40.5</span><span class="p">));</span>
</code></pre></div></div>
<p>There’s still more room for improvement, but you get the point.</p>
<p>So, “why should I consider a passthrough design?”, you may wonder! Here are some reasons why:</p>
<ul>
<li>
<p>Passthroughs allow you to completely maintain your own code when working with a team of developers. That is to say your code needs not be scattered around, nor will anyone need direct access to any of your functions; you make your inner functions private, provide a <code class="language-plaintext highlighter-rouge">passthrough</code> function and there you roll ^_^.</p>
</li>
<li>
<p>Documentation becomes a breeze. Think about it. Instead of having to document every single function and provide snippets and use cases, you can keep all these functions private and only worry about documenting one: your <code class="language-plaintext highlighter-rouge">passthrough()</code> function. This can save you lots and lots of time.</p>
</li>
</ul>]]></content><author><name>Fadi Hanna Al-Kass</name></author><category term="Rust" /><summary type="html"><![CDATA[When writing libraries, APIs, and SDKs, the less stuff you ask your user to memorize the better it looks to you and feels to them. For instance, if you were to write a Math library that performs some arithmetic operations, you could write your library functions as so:]]></summary></entry><entry><title type="html">Enum and Match Systems in Rust</title><link href="/Enum-and-Match-Systems-in-Rust/" rel="alternate" type="text/html" title="Enum and Match Systems in Rust" /><published>2017-06-17T05:00:00+00:00</published><updated>2017-06-17T05:00:00+00:00</updated><id>/Enum%20and%20Match%20Systems%20in%20Rust</id><content type="html" xml:base="/Enum-and-Match-Systems-in-Rust/"><![CDATA[<p>You’ve probably worked with <code class="language-plaintext highlighter-rouge">enums</code> before, but if you haven’t, they’re basically a way to have a selection out of a number of different options. A <code class="language-plaintext highlighter-rouge">Person</code> struct could contain a <code class="language-plaintext highlighter-rouge">gender</code> field that points to an enum of three options (<code class="language-plaintext highlighter-rouge">Male</code>, <code class="language-plaintext highlighter-rouge">Female</code>, and <code class="language-plaintext highlighter-rouge">Undisclosed</code>), i.e.:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">enum</span> <span class="n">PersonGender</span> <span class="p">{</span>
<span class="n">MALE</span><span class="p">,</span>
<span class="n">FEMALE</span><span class="p">,</span>
<span class="n">UNDISCLOSED</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">struct</span> <span class="n">Person</span> <span class="p">{</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="n">age</span><span class="p">:</span> <span class="nb">i8</span><span class="p">,</span>
<span class="n">gender</span><span class="p">:</span> <span class="n">PersonGender</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">person</span> <span class="o">=</span> <span class="n">Person</span> <span class="p">{</span>
<span class="n">name</span><span class="p">:</span> <span class="s">"Fadi Hanna Al-Kass"</span><span class="nf">.to_string</span><span class="p">(),</span>
<span class="n">age</span><span class="p">:</span> <span class="mi">27</span><span class="p">,</span>
<span class="n">gender</span><span class="p">:</span> <span class="nn">PersonGender</span><span class="p">::</span><span class="n">MALE</span><span class="p">,</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now, what if a person so chooses to identify as something else? In that case, you could add a 4th option (<code class="language-plaintext highlighter-rouge">Other</code>) and attach a value of type <code class="language-plaintext highlighter-rouge">String</code> to it. Here’s what your end result would look like:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">enum</span> <span class="n">PersonGender</span> <span class="p">{</span>
<span class="n">MALE</span><span class="p">,</span>
<span class="n">FEMALE</span><span class="p">,</span>
<span class="n">UNDISCLOSED</span><span class="p">,</span>
<span class="nf">OTHER</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span>
<span class="p">}</span>
<span class="k">struct</span> <span class="n">Person</span> <span class="p">{</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="n">age</span><span class="p">:</span> <span class="nb">i8</span><span class="p">,</span>
<span class="n">gender</span><span class="p">:</span> <span class="n">PersonGender</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">person</span> <span class="o">=</span> <span class="n">Person</span> <span class="p">{</span>
<span class="n">name</span><span class="p">:</span> <span class="s">"Jake Smith"</span><span class="nf">.to_string</span><span class="p">(),</span>
<span class="n">age</span><span class="p">:</span> <span class="mi">27</span><span class="p">,</span>
<span class="n">gender</span><span class="p">:</span> <span class="nn">PersonGender</span><span class="p">::</span><span class="nf">OTHER</span><span class="p">(</span><span class="s">"Agender"</span><span class="nf">.to_string</span><span class="p">()),</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Of course <code class="language-plaintext highlighter-rouge">enums</code> don’t have to be part of a struct, and <code class="language-plaintext highlighter-rouge">enum</code> values don’t have to be primitives either. An <code class="language-plaintext highlighter-rouge">enum</code> value can point to a <code class="language-plaintext highlighter-rouge">struct</code> or even another <code class="language-plaintext highlighter-rouge">enum</code> and so on. For instance, you can write a function that returns a status that’s either <code class="language-plaintext highlighter-rouge">PASS</code> or <code class="language-plaintext highlighter-rouge">FAILURE</code>. <code class="language-plaintext highlighter-rouge">PASS</code> can include a string while <code class="language-plaintext highlighter-rouge">FAILURE</code> can contain more information about the severity of the failure. This functionality can be achieved as so:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">enum</span> <span class="n">SeverityStatus</span> <span class="p">{</span>
<span class="nf">BENIGN</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span>
<span class="nf">FATAL</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span>
<span class="p">}</span>
<span class="k">enum</span> <span class="n">FunctionStatus</span> <span class="p">{</span>
<span class="nf">PASS</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span>
<span class="nf">FAILURE</span><span class="p">(</span><span class="n">SeverityStatus</span><span class="p">),</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">compute_results</span><span class="p">()</span> <span class="k">-></span> <span class="n">FunctionStatus</span> <span class="p">{</span>
<span class="c1">// Successful execution would look like the following:</span>
<span class="c1">// return FunctionStatus::PASS("Everything looks good".to_string());</span>
<span class="c1">// While a failure would be indicated as follows:</span>
<span class="k">return</span> <span class="nn">FunctionStatus</span><span class="p">::</span><span class="nf">FAILURE</span><span class="p">(</span><span class="nn">SeverityStatus</span><span class="p">::</span><span class="nf">FATAL</span><span class="p">(</span><span class="s">"Continuing beyond this point will cause more damage to the hardware"</span><span class="nf">.to_string</span><span class="p">()));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now onto <code class="language-plaintext highlighter-rouge">match</code>. One of the things I love the most about <code class="language-plaintext highlighter-rouge">match</code> is its ability to unstructure objects. Let’s take a second look at our last code snippet and see how we can possibly handle the response coming back to us from <code class="language-plaintext highlighter-rouge">compute_results()</code>. For this, I’d definitely use a set of <code class="language-plaintext highlighter-rouge">match</code> statements, e.g.:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">compute_results</span><span class="p">();</span>
<span class="k">match</span> <span class="n">res</span> <span class="p">{</span>
<span class="nn">FunctionStatus</span><span class="p">::</span><span class="nf">PASS</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="c1">// Handling a PASS response</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"PASS: {}"</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span>
<span class="p">}</span>
<span class="nn">FunctionStatus</span><span class="p">::</span><span class="nf">FAILURE</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="c1">// Handling a FAILURE response</span>
<span class="k">match</span> <span class="n">x</span> <span class="p">{</span>
<span class="nn">SeverityStatus</span><span class="p">::</span><span class="nf">BENIGN</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="c1">// Handling a BENIGN FAILURE response</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"BENIGN: {}"</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="p">}</span>
<span class="nn">SeverityStatus</span><span class="p">::</span><span class="nf">FATAL</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="c1">// Handling a FATAL FAILURE response</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"FATAL: {}"</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now, if you happen to add more options to any of the two <code class="language-plaintext highlighter-rouge">enums</code> (say, a <code class="language-plaintext highlighter-rouge">WARN</code> option to <code class="language-plaintext highlighter-rouge">FunctionStatus</code> or <code class="language-plaintext highlighter-rouge">UNCATEGORIZED</code> to <code class="language-plaintext highlighter-rouge">SeverityStatus</code>), the compiler will refuse to compile your code until all possible cases are handled. This is definitely a plus as it forces you to think about all the paths your code could take.</p>
<p>However, there will be times when you really only want to handle specific cases and not the rest. For instance, we may only be interested in handling the case of failure of <code class="language-plaintext highlighter-rouge">compute_results()</code> and ignore all passes. For that you could use the <code class="language-plaintext highlighter-rouge">_</code> case. <code class="language-plaintext highlighter-rouge">_</code> in the case of a <code class="language-plaintext highlighter-rouge">match</code> statement or expression means “everything else”. So, to write our <code class="language-plaintext highlighter-rouge">FunctionStatus</code> handling functionality in a way when only failures are handled, we could do the following:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="nf">compute_results</span><span class="p">();</span>
<span class="k">match</span> <span class="n">res</span> <span class="p">{</span>
<span class="nn">FunctionStatus</span><span class="p">::</span><span class="nf">FAILURE</span><span class="p">(</span><span class="n">severity</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="k">match</span> <span class="n">severity</span> <span class="p">{</span>
<span class="nn">SeverityStatus</span><span class="p">::</span><span class="nf">FATAL</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"FATAL: {}"</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="nn">SeverityStatus</span><span class="p">::</span><span class="nf">BENIGN</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"BENIGN: {}"</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>