A New Programmer Kicks a Roadblock

The time I composed my first program can be back to my junior high school age. It was the first day of PC lesson, and everybody crowded to the computer classroom. We were told to learn “programming” there. The kids who were talented would be selected and trained for OI . Others instead would go to an ordinary class and learn something more general.

I was anxious. Before the time I had no concept of what “programming” is, nor had I ever gone through a real PC lesson. The PC lesson in my primary school barely taught anything. Over the time the teachers let us play games instead. I could type merely a dozen of characters per minute, since I’d never received a thorough typing training. I was ignorant of inside the metal box. I was a complete computer idiot.

But some of my classmates did. They typed swiftly like wind, they knew how to play with the operating system, and what’s more, they were chattering excitedly about things like “C language”, “array” or “for-loop”, words I’d never heard of.

I sit in front of a monitor and the class began. The teacher said we were going to learn a language named “Pascal”, and she instructed us to open the “Free Pascal IDE”. I followed a few clicks through a cascaded menu and finally reached the item. A window popped out.

clip>2022-09-20-fpc.png!width=600

The screenshot was taken on my Ubuntu recently, but at the time it was on Windows 7 and looked slightly different. Not many people these days have heard of the Pascal language, and fewer have seen this antique interface.

It was the weirdest interface I had ever seen. The IDE was like another system trapped in a small unresizable window , with queerly rendered icons and widgets. The menu wouldn’t expand on cursor hovering. The editor wouldn’t scroll when I wheel my mouse. And most importantly, there was English everywhere, which frightened me.

The teacher then showed us our first program to type. It was a simple one that reads an integer from one file, and writes its square to another. The code was like

program program1;
var
a: integer;
begin
assign(input, 'program1.in'); reset(input);
assign(output, 'program1.out'); rewrite(output);
read(a);
writeln(a * a);
close(input); close(output);
end.

It took me quite a while to put these lines onto the screen, and more time to “save the code as a file”. Before the day I had no idea of what a “file” is, plus the file selector of IDE was not ergonomic at all. After saving I just noticed an icon with title program1.pas popped out in the Windows file explorer. Then I hit the Compile menu entry. More icons popped out, including one named program1.exe — and that was my program.

The next to figure out was how to run the program, which was comprised of several complicated steps.

The first thing I should do is to right-click in the file explorer, select the “New -> Text Document” entry, and rename it to program1.in. The OS would prompted me as I’ve changed the file extension, but I should click “Yes”. Then right-click on the created file, select “Open with…” and choose “Notepad” in the dialog. In the notepad type an integer like 3, save and close it.

By now the input was prepared, and I should double-click the program1.exe file to execute the program. A black window flashed by, and one more icon with title program1.out appeared. Open it with the same trick as input file, where I saw the result number 9.

Woah, that was amazing. Within 40 minutes I’d created something “intelligent”, albeit excessively simple, working faithfully whatever number I fed .

In company with the flood of joy, however, there goes the frustration. It aroused a feeling that programming is complicated as ordering a banquet for a serious occasion, with so much doctrinal detail to care about. What upset me the most is, I spent most of my time fighting against irrelevant issues, but caught little idea about true programming throughout the class hour. The reason is that I lacked certain understanding about the OS beneath, without which one could go nowhere on the trip towards programming.

And there exists another question — is interacting with a program always so painful? Of course not, but until several months later did I realize the assign(...) statements were not a necessity of an integral program, and there’s so called “command line interface” where you can type the input easily and immediately get the result. The awkward interaction bridged by files was actually dedicated for OI evaluation, as I knew afterwards. It took me one year to understand the ABC of GUI programs, when I built my first Form-based application with Delphi. My program no longer shipped with an ugly black window! And it unlocked varied interaction as the ones for daily use. After more years, with a broader understanding of programming I get, I am able to create websites, mobile apps or anything fit in my requirement. But for a 12-year-old kid at the time, the first program was just not appealing and NOT COOL at all.

The class, of course, was not designed for teaching cool things. It was for choosing talented guys towards a specific target. But over the years, I kept seeing people who were new to programming and struggled at half way, for one reason or another. This makes me consider about the root obstacle for a new guy to learn programming.

The way they are taught is no doubt a fundamental factor. Learners should be motivated so as to earn confidence. I used to know some power users who get started with programming smoothly and swiftly. They have clear goals for programming, some to tweak the system behavior and others to automate daily work. They learn the minimal knowledge by documentation or blog posts, and then come up with a prototype program which accomplishes the job. The entire process is interesting and fulfilling.

But for elementary learners, this does not always apply. Most of them are aimless, having no idea what programming can be used for. What’s worse, they are taught to use inappropriate tooling, deteriorating the learning to some boring and painful nightmare.

I can remember in the Programming 101 of my college around six years ago, we were taught C and to use the obsolete Visual C++ 6.0 IDE. The compulsory course was rather like a math one, where most time was spent in the classroom reading slides, and homework was handwritten to figure out the result of code fragments. The merely four coding tasks were to implement some algorithms and data structures, fairly dull. Some of the classmates had no deep knowledge of computers, or even didn’t use before (since mobile devices were popularized). They went through a hard time to understand low-level concepts like pointers, and were desperate in finishing the coding tasks. They learnt for the exams, with little or no interest, and soon forgot the things in one or two semesters.

I am not claiming languages like C at low-level is not suitable as the first language — for those will major in computer science, they demonstrate well how the machine works. But other learners deserve a much modern language at a higher level, plus a coding environment that will hide off obscure machine detail. The language and tooling should ease the hurdle to create appealing projects.

The language we do have, like Python. It’d better to be young or carefully designed, so that backward compatibility won’t cause too much confusing syntax. It should support imperative paradigm so as not to blow the learner’s brain (unless for mathematicians), but not limited to this for going further. And most importantly, it should conceal the low-level stuff to better illustrate the basic idea of programming.

But the tooling we don’t, at least not perfect. Lots of work should be done to create such a layer between OS and ignorant learners, and should be done perfectly well without bugs. I’ve seen bugged programming environment leaked more detail about the underlying support, causing its users frustrated and frightened.

The need of domain-specific learners may also be noticed. Some people learn programming to improve the productivity in their expertised fields, e.g., data analysis or financial trading. Like power user, they would be fulfilled if the first few programs can assist the jobs, but from time to time that’s not the case. The guidance or tools, however, are often poorly crafted, probably because there’re few professional programmers in the field.

Over the time I have witnessed programming languages and toolchains evolving, which enables the chance for skilled guys to build faster and safer programs more easily, but the learning curve of 0 to 1 benefits not much from the trend. I am expecting to see it change in the future.


Git-based Dependencies in Dart and Go

Both Dart and Go support decentralized package distribution. One is able to directly adopt an existing git repository as dependency, easing the effort of distributing packages.

Sometimes we might expect more fine-grained control on what to pull from a git repository. For example, to lock a package’s version, we would specify a particular tag, commit or branch name to pull from. Or if it’s a mono-repo, we would choose a sub-directory from the repository root. This post summarizes how to achieve these purposes in both languages.

Read More


Reversy Naming

I am always a dedicated fan of writing naturally readable code – by “naturally readable” I mean, one can read a line of code as if it were a sentence of English (or maybe other human languages). It’s believed that the practice encourages more self-explainable code, as the code reads more like a human-composed article, instead of some gibberish only recognizable by machine.

The practice recommends to name functions or variables following the word order of human language, for English that is, subjects come after verbs, and adjectives go before nouns that being modified. The samples below showcase how it guides naming in a program (please hold your opinions about the casing)

  • append_to_list(lst, item). A function that appends an item to a list, which can read as “append to the list (specified by name lst) with the item”.
  • register_service_notifier(func). A function that registers another function as a service notifier, which can read as “register a service notifier with the function func“.
  • UserFollowersListView. The name of a web component which is a list view to display followers for a user.

It plays well and improves my developing experience most of the time, but there is no silver bullet, just like other practices or guidelines.Sometimes I found the readability even degrades. I kept skimming the lines and just couldn’t locate an item efficiently.

Read More


人类一败涂地

轻微的一阵异响。面前说话的她随即模糊起来,声音也渐渐远去,趋于缥缈。我这才注意到从一开始就没有看清她的脸——原来只是个梦罢了。意识跌落回现实。我又重新感受到了我的双腿,久坐后腰的酸痛,最后是沉重的眼皮。睁开眼,还是熟悉的银色舷窗。

窗外的天王星已经很大了。坐了这么多次,光看天王星的大小也能知道到哪了,估计还得两个小时才能下船。我伸了个懒腰,腿上的便携式电脑差点飞了起来,屏幕被点亮了,光标停在了讲稿的最后一行,冷冷地跳动着。

再读一遍吧。到那边可有得我忙的。

周围的人大多和我一样,要么在闭目养神,要么在低头对着电脑,大家都一言不发。长途旅行最能磨去一个人的精气了,但为了工作你不得不奔波于各个星球之间——真是个乏味的时代。但有一个人不一样。

“孩子,那就是天王星了吧?”

Read More


Invalid Golang Pointers Can Bite You Even If You Don't Dereference

In Golang, if you coerce a uintptr variable into unsafe.Pointer (or further, to some *T), the linter will warn with the message "possible miuse of unsafe.Pointer". This makes sense because the uintptr variable may contain an address that points to a piece of invalid memory, and dereferencing such a pointer is catastrophic (usually aborts the program).

I was always aware of the above discipline, but I thought it would be OK to hold the pointers but not dereference them. This is true in C/C++, but not for Golang, which I did not realize until recently.

In fact, the program can panic even if you just keep an invalid pointer on the stack!

Read More


Side Project(副业)

计算机从业者们似乎都喜欢写 side project,这在中文社区中有个通俗的说法即「搞副业」。如果你经常逛 V2EX、Reddit 的编程板块或是 Hacker News,你会看到人们分享的各种各样的 side project,小到一个百余行代码的实用小工具,大至一个框架、一个网站乃至一个完整的准商业项目。

人们在分享自己的创造时往往怀着极大的热情。这是一种即使隔着屏幕也能感受到的心情,就像七岁的男孩组装好了第一辆四驱车,又或是料理爱好者凭自己的努力烧了一顿高难度的饭菜。他们分享的是自己的宝贝,并期望在人群中掀起波澜。在一些社区如 r/rust,人们热衷于讨论这样的分享,给予肯定以及有意义的反馈。但事情并不总是如意,在另外一些地方,如综合性的或是冷门的社区,只有少数分享会被人们注意,更多的则是被略过,直至沉没在信息流中。这通常会令人沮丧。

Read More


A Flaw of Promoting Complex Trait Bounds in Rust

Days ago, for some reason, I was trying to implement a function that can polymorphize over its return type. The solution is simple, but my brain was jammed at that time, trapped in some complicated typing tricks for hours.

During the struggling, I coincidently ran into something that is temporarily a flaw in the current Rust compiler implementation. In some cases, the compiler is not smart enough to promote known trait bounds, and we have to replicate them again and again. Although the problem is afterwards proved to be a useless “X-Y Problem”, I would still like to share the story.

Read More


Initialize Process Pool Worker with Individual Value

There could be scenes when you are using multiprocessing.pool.Pool and you want to perform some initialization for each worker before tasks are scheduled via Pool.map() or something alike. For example, you create a pool of 4 workers, each for one GPU, and expect tasks scheduled on Worker-i to precisely utilize GPU-i. In this case, Worker-i should be initialized with env var CUDA_VISIBLE_DEVICES=<i> set.

To initialize spawned workers, the constructor of Pool provides two arguments concerning the job initializer and initargs. initializer is expected to be a callable, and if specified, each worker process will call initializer(*initargs) when it starts.

import multiprocessing as mp
import multiprocessing.pool as mpp

def worker(arg1):
print(arg1)

mpp.Pool(processes=2, initializer=worker, initargs=(42, ))
# 42
# 42

This is, however, slightly away from what we expect. The initializer is called with same arguments in each worker, while in our case, the arguments are expected to be different, like value 1 for Worker-0 and value 1 for Worker-1. There are two approaches to do the tricks.

Use a Queue

Queue and SimpleQueue types in module multiprocessing implement multi-producer, multi-consumer FIFO queues under the multi-processing scenario. We may create and share a queue among parent and worker processes, send individual values from parent processes and read them from workers. Since the sending and receiving operations are synchronized, we won’t run into any race conditions.

def worker(q):
print(q.get())

q = mp.SimpleQueue()
p = mpp.Pool(processes=2, initializer=worker, initargs=(q,))
for i in range(2):
q.put(i)
p.close()
# 0
# 1

Use a Value

Alternatively, we may use a lighter shared object other than a queue. The Value type in module multiprocessing allows sharing simple values across multiple processes. It can also synchronize accesses to values to avoid race conditions if necessary. We can use a Value object to allocate an individual id for each worker process.

def worker(v):
with v.get_lock():
val = v.value
v.value += 1
print(val)

v = mp.Value(ctypes.c_int32, 0, lock=True)
p = mpp.Pool(processes=2, initializer=worker, initargs=(v,))
p.close()
# 0
# 1

Rust - Python FFI From Scratch

I was recently working on a side project that involves communication between binaries written in Rust and web interfaces written in Python. Moving a part of my project onto a language like Rust is under several considerations: 1) the logic is all about manipulating byte arrays, where Python has deficit and system language like Rust is superior; 2) the logic happens to be complicated, I need a static type system to ensure the correctness, and also the match expression of Rust is found helpful in getting things concise; 3) I was planning to develop CLI tools with Rust, which calls this fraction of functionality, and I don’t want to rewrite the stuff in the future.

Read More


[Extending Hexo For My Site] Part 1 - Better Mathjax Rendering

I am a heavy user of Mathjax. Mathjax is a library that renders Tex-compatible syntax into pretty equations in web scenarios. Hence I am always mixing up Markdown and Tex snippets in my writing. The annoying part is Tex snippets have low priority in my Markdown renderer, and are sometimes incorrectly rendered into Markdown elements. For instance, $a_1, a_2$ becomes $a<em>1, a</em>2$, where underscores within $...$ are mistakenly recognized as an emphasis element. A bunch of escaping is required to avoid the situation, which drives me mad. So I got to seek a permanant solution.

Read More