<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tonghe Wang</title>
    <description>The latest articles on DEV Community by Tonghe Wang (@t0nghe).</description>
    <link>https://dev.to/t0nghe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F274098%2F1b27d7ad-7346-422c-b23f-beebf241b790.jpeg</url>
      <title>DEV Community: Tonghe Wang</title>
      <link>https://dev.to/t0nghe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/t0nghe"/>
    <language>en</language>
    <item>
      <title>Some thoughts on Rust and Elm</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Sun, 05 Mar 2023 12:00:23 +0000</pubDate>
      <link>https://dev.to/t0nghe/some-thoughts-about-rust-and-elm-2emn</link>
      <guid>https://dev.to/t0nghe/some-thoughts-about-rust-and-elm-2emn</guid>
      <description>&lt;p&gt;Last week, my friend Joe asked me what's the best way to learn a programming language. &lt;/p&gt;

&lt;p&gt;I replied: Go through the basics as quickly as possible. Then begin building things with it. This is how I learn Golang. &lt;/p&gt;

&lt;p&gt;I had been curious about Rust for a while. And a coworker talked about how Rust was his favorite language with a lot of exuberance. I thought to myself, maybe I could do the same with Rust.&lt;/p&gt;

&lt;p&gt;I was intimidated by “&lt;a href="https://doc.rust-lang.org/book/"&gt;the Rust book&lt;/a&gt;”. It's a huge book of I don't know how many pages. And I never got past hello world and the curious exclamation mark after &lt;code&gt;println&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's when I discovered &lt;a href="https://tourofrust.com/"&gt;Tour of Rust&lt;/a&gt; after some random Googling. Tour of Rust is a pleasant introduction to the basic syntax and concepts of Rust. With a compiler on the right side of the page, it adds some nice interactivity to the tutorial. It makes it easier to understand when you can try and change things and see how it fails.&lt;/p&gt;

&lt;p&gt;So far my feeling is a few concepts (borrowing and referencing) in Rust are quite clever. I don't understand under what circumstances lifetime needs to be managed manually. Then it feels like a few things are added as an afterthought, which leads to a certain degree of internal incongruity in its syntax.&lt;/p&gt;

&lt;p&gt;Yet despite the tribal sentiment among Go developers and Rust developers, these languages feel more similar than different.&lt;/p&gt;

&lt;p&gt;Curiously, after searching Rust on YouTube, the algorithm god recommended a million Elm talks with one of them promising &lt;a href="https://www.youtube.com/watch?v=kuOCx0QeQ5c"&gt;to give you happiness&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Incidentally, I read a blog post from the Warp team about &lt;a href="https://www.warp.dev/blog/why-is-building-a-ui-in-rust-so-hard"&gt;building a UI in Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In a gist, it was difficult to build a UI in Rust if they followed the &lt;a href="https://docs.flutter.dev/development/ui/widgets-intro"&gt;widget tree&lt;/a&gt; approach of Flutter. Because multilayers of object inheritance do not feel natural or intuitive in Rust.&lt;/p&gt;

&lt;p&gt;Although they used a close but different approach, the Model-View-Update approach used in the &lt;a href="https://guide.elm-lang.org/architecture/"&gt;Elm architecture&lt;/a&gt; was an inspiration for the Warp team.&lt;/p&gt;

&lt;p&gt;To use an inaccurate analogy in React terms, &lt;code&gt;Model&lt;/code&gt; is like &lt;code&gt;Redux&lt;/code&gt;, it manages all the states in your entire app. &lt;code&gt;View&lt;/code&gt; manages the virtual DOM that renders the page as the states change. &lt;code&gt;Update&lt;/code&gt; makes changes to the state upon receiving messages (events) when the user interacts with your app. Pretty neat.&lt;/p&gt;

&lt;p&gt;What's charming about Elm is it's easier, way easier, linting and debugging that works out of the box. You don't need to configure anything, it just works. This is so much better than React.&lt;/p&gt;

&lt;p&gt;But you do need to learn a new language and get used to the functional programming way of thinking.&lt;/p&gt;

&lt;p&gt;Bottom line: Rust and Elm are both fun. Don't know if or when they will be useful at work. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Go GUI: Trying out Fyne</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Sun, 09 Oct 2022 20:33:59 +0000</pubDate>
      <link>https://dev.to/t0nghe/go-gui-trying-out-fyne-1j3f</link>
      <guid>https://dev.to/t0nghe/go-gui-trying-out-fyne-1j3f</guid>
      <description>&lt;p&gt;The idea of building a piece of software once and run it everywhere is certainly charming. And Go supports cross-compiling out of the box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fyne.io/" rel="noopener noreferrer"&gt;Fyne&lt;/a&gt; is a very promising GUI package for Go that helps you build a GUI app and cross-compile it all devices and OSes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Heres is a simple example
&lt;/h2&gt;

&lt;p&gt;This code gives you a small window with a label and input field. Grab this piece of code, init a mod and tidy it, and you are good to go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/app"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/widget"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/container"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, you!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello! What is your name?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEntry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetPlaceHolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Input your name..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewVBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShowAndRun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we define an app in &lt;code&gt;a&lt;/code&gt;. Then we define a window &lt;code&gt;w&lt;/code&gt; with title “Hello, you!”. &lt;/p&gt;

&lt;p&gt;Then we create a new label and a new input field (entry). These are all “widgets”. So their constructors are inside the &lt;code&gt;widget&lt;/code&gt; package. We set a placeholder for the input field for good measure.&lt;/p&gt;

&lt;p&gt;Next we create a vertical box (which is a container) and set it as the content of the window &lt;code&gt;w&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When we build and run this program, this is how it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftonghe.xyz%2Fassets%2F221009-fyne-resize-cjk-tofu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftonghe.xyz%2Fassets%2F221009-fyne-resize-cjk-tofu.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might have noticed the quirks. When you resize the window, you can see the content shivers. This is because Fyne tries to automatically adjust the window size and layout.  &lt;/p&gt;

&lt;p&gt;And when you try to display something that's not rendered by the default typeface, it becomes a block. CJK characters, Arabic letters and emojis are all mangled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a custom font
&lt;/h2&gt;

&lt;p&gt;In order to correctly display Unicode characters, you need to bundle a custom font and include it in your custom theme. Then this font is applied globally to your app as part of the theme. From what I read the issues section, as of now &lt;a href="https://github.com/fyne-io/fyne/issues/3245#issuecomment-1239283988" rel="noopener noreferrer"&gt;only TTF is supported&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I downloaded &lt;a href="https://source.typekit.com/source-han-serif/" rel="noopener noreferrer"&gt;Source Han Serif&lt;/a&gt; in TTF format. And ran this command to &lt;a href="https://developer.fyne.io/extend/bundle" rel="noopener noreferrer"&gt;bundle&lt;/a&gt; it as a resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fyne bundle SourceHanSerifSC.ttf &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; bundled.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next thing we do is &lt;a href="https://github.com/fynelabs/notes/blob/main/theme.go" rel="noopener noreferrer"&gt;get a theme&lt;/a&gt; from one of Fyne's demo apps – “Notes”. &lt;/p&gt;

&lt;p&gt;The only thing we need to do is change the name of the font in &lt;code&gt;Font()&lt;/code&gt; method in &lt;code&gt;theme.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;myTheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;fyne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fyne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resourceSourceHanSerifSCTtf&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? Not bad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftonghe.xyz%2Fassets%2F221009-fyne-data-binding.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftonghe.xyz%2Fassets%2F221009-fyne-data-binding.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Data-binding
&lt;/h2&gt;

&lt;p&gt;I grabbed the theme from Fyne Notes and didn't change the color. That explains the yellow background color. New theme is applied by calling the &lt;code&gt;SetTheme()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;In this example, whenever the user types in or clears the text field, the greeting changes. This is done by setting up data-binding. (If the action to link two things is “binding”, then each of the two things are “bound” together. I guess I'll call them “bound variables” and “bound widgets”.)&lt;/p&gt;

&lt;p&gt;First we need to declare bound string variables. Then we need to use these variables to create bound widgets. Note you use &lt;em&gt;different&lt;/em&gt; methods to create bound widgets.&lt;/p&gt;

&lt;p&gt;At this point, we need to link the two bound variables. There are methods that allow bi-directional conversion between a number and a string. Some conversion methods even support string formats. There's also a method to convert strings to and from a URI.&lt;/p&gt;

&lt;p&gt;But it seems the only way to change &lt;code&gt;greeting&lt;/code&gt; whenever &lt;code&gt;userinput&lt;/code&gt; changes is adding a listener. To add a listener, you need to create a data listener from an anonymous function. &lt;/p&gt;

&lt;p&gt;With this, whenever &lt;code&gt;userinput&lt;/code&gt; changes, the callback function is executed. Notice how we &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; the value of a bound variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/app"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/widget"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/container"&lt;/span&gt;
    &lt;span class="s"&gt;"fyne.io/fyne/v2/data/binding"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// Setting the theme. `myTheme` is defined in `theme.go`&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;myTheme&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"你好 Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Declare two binding string variables&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;userinput&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Adding a listener&lt;/span&gt;
    &lt;span class="n"&gt;userinput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDataListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userinput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"你叫什么名字？&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;What is your name?"&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"你好，%s！&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Hello, %s!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;

    &lt;span class="c"&gt;// Creating binding widgets&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLabelWithData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEntryWithData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userinput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewVBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShowAndRun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A few words
&lt;/h2&gt;

&lt;p&gt;I tried two other pure-Go GUI packages. They are &lt;a href="https://gioui.org/" rel="noopener noreferrer"&gt;Gio&lt;/a&gt; and &lt;a href="https://nuxui.org/" rel="noopener noreferrer"&gt;Nuxui&lt;/a&gt;. Both are ingenious projects. (There are quite a few other packages that help bind Go apps to more established GUI engines.)&lt;/p&gt;

&lt;p&gt;Gio seems much more flexible than Fyne. And the way it uses contexts and channels seems more Go-ish. But typing Chinese in the input field simply doesn't work. The way an IME for CJK works is you type a sequence of letters, a popup menu shows up, from which you to choose a character or a word. Ideally, when an IME is active, keydown events should not be registered. The input field should only get data when a word has been composed in IME and is “committed” (selected by the user). But when you type in Gio's default input field, each letter in the sequence, as well the committed word, are all registered in the input field. This probably has to do with how Gio handles keyboard events. &lt;/p&gt;

&lt;p&gt;Nuxui uses a backtick-wrapped string to declaratively define the UI. This is way less cumbersome than calling a bunch of nested constructors. I didn't spend too much time on it as breaking changes are introduced to some basic functions from v0.6 to 0.8. This resulted in some sample projects failing to compile. &lt;/p&gt;

&lt;p&gt;I spent the most time on Fyne because Fyne is the best documented among the three. There are a few demo videos and &lt;a href="https://github.com/PacktPublishing/Building-Cross-Platform-GUI-Applications-with-Fyne" rel="noopener noreferrer"&gt;even a book&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Fyne is designed with unit testing in mind. It provides helper functions to mock events. It supports comparing to snapshots to ensure correct rendering of UI.&lt;/p&gt;

&lt;p&gt;Fyne is also well structured. Although so much so that it occasionally feels there's too much boilerplate.&lt;/p&gt;

&lt;p&gt;But all in all, Fyne is great and very promising. I had a great time playing with it. I'm sure you will too. &lt;/p&gt;

</description>
      <category>go</category>
      <category>fyne</category>
      <category>gui</category>
    </item>
    <item>
      <title>#15</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Wed, 05 Oct 2022 08:35:34 +0000</pubDate>
      <link>https://dev.to/t0nghe/15-34c8</link>
      <guid>https://dev.to/t0nghe/15-34c8</guid>
      <description>&lt;h2&gt;
  
  
  Table-driven tests
&lt;/h2&gt;

&lt;p&gt;Go has superb built-in support for good programming practices, such as test-driven development. In fact, I'm learning a lot about TDD while learning Go from this book: “&lt;a href="https://quii.gitbook.io/learn-go-with-tests/"&gt;Learn Go with Tests&lt;/a&gt;”. &lt;/p&gt;

&lt;p&gt;If you want to test a bunch of similar inputs and outputs, it's handy to run table-driven tests. What you do is list input values and expected output in an array, then loop through all the test cases.&lt;/p&gt;

&lt;p&gt;I found this &lt;a href="https://lorenzopeppoloni.com/tabledriventestspy/"&gt;blog post by Lorenzo Peppoloni&lt;/a&gt; quite helpful. It gives examples in both Golang and Python for table-driven tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create your own keyboard layout optimized to reduce finger fatigue
&lt;/h2&gt;

&lt;p&gt;We all push buttons for a living. Most of us spend enormous amount of time with the Qwerty keyboard layout. &lt;/p&gt;

&lt;p&gt;I came across this fascinating video about &lt;a href="https://www.youtube.com/watch?v=EOaPb9wrgDY"&gt;making your own perfect keyboard layout&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By perfect, “adumb” refered to the shortest distance your fingers travel while typing on the keyboard. And the corpus he used to calculate the total distance is arXiv abstracts.&lt;/p&gt;

&lt;p&gt;He first randomly generated keyboard layouts then crossed over the best ones. Until after 1000 generations of crossover, the total finger travel distance stopped decreasing.&lt;/p&gt;

&lt;p&gt;If I were to make a keyboard layout, I would use a larger corpus that includes English, Swedish, Chinese as typed using Pinyin, and a bunch of programming languages. &lt;/p&gt;

&lt;p&gt;On top of the larger number of symbols to rearrange, when you type CJK (and other complex, non-alphabetic) languages, you need to deal with the complicated relationship between the &lt;a href="https://en.wikipedia.org/wiki/Input_method"&gt;input method&lt;/a&gt; and the keyboard layout, especially on Linux.&lt;/p&gt;




&lt;h2&gt;
  
  
  zsh
&lt;/h2&gt;

&lt;p&gt;For quite a while, I found I couldn't use commands I clearly had installed properly (macOS 12.2).&lt;/p&gt;

&lt;p&gt;After some digging, I used an &lt;code&gt;export&lt;/code&gt; command in &lt;code&gt;.zshrc&lt;/code&gt; file and forgot to include &lt;code&gt;$PATH:&lt;/code&gt; when setting the PATH value. &lt;/p&gt;

&lt;p&gt;This &lt;a href="https://stackoverflow.com/a/71099236/13776347"&gt;answer on StackOverflow&lt;/a&gt; was helpful. &lt;/p&gt;

</description>
      <category>tdd</category>
      <category>zsh</category>
      <category>keyboard</category>
    </item>
    <item>
      <title>Using prepared statements &amp; pointers in Golang</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Tue, 26 Jul 2022 18:36:00 +0000</pubDate>
      <link>https://dev.to/t0nghe/using-prepared-statements-pointers-in-golang-4oip</link>
      <guid>https://dev.to/t0nghe/using-prepared-statements-pointers-in-golang-4oip</guid>
      <description>&lt;p&gt;In MySQL, you can use a question mark (?) in a prepared statement to stand in for a value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbconn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`SELECT id FROM user
    WHERE name="?";`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// (1) - BAD&lt;/span&gt;
  &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dbconn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`SELECT id FROM user
    WHERE name=?;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// (2) – GOOD&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// (3)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Go code above, &lt;code&gt;dbconn&lt;/code&gt; is a connection to a MySQL server. Line 1 defines a prepared statement. And Line 3 queries the table for a row where the &lt;code&gt;name&lt;/code&gt; column matches the value of variable &lt;code&gt;name&lt;/code&gt;. I assumed the &lt;code&gt;?&lt;/code&gt; in this query would be interpolated with an actual string. I added quotation marks since they are needed around strings in MySQL CLI.&lt;/p&gt;

&lt;p&gt;This fails to return anything. Removing the quotation marks solved the problem. The correct code is on Line 2.&lt;/p&gt;

&lt;p&gt;I also find Line 3 quite interesting. Here, first, &lt;code&gt;stmt.QueryRow()&lt;/code&gt; returns a pointer to a &lt;code&gt;sql.Row&lt;/code&gt; object. Its &lt;code&gt;Scan()&lt;/code&gt; method then does two fascinating things: a) it sets a “&lt;a href="https://pkg.go.dev/database/sql#Out.Dest"&gt;dest&lt;/a&gt;” to the output value and b) returns an error if there's an error or &lt;code&gt;nil&lt;/code&gt; if there's no error.&lt;/p&gt;

&lt;p&gt;Thingy &lt;code&gt;a&lt;/code&gt; is quite interesting. In this case, &lt;code&gt;Scan()&lt;/code&gt; method will find the memory address of variable &lt;code&gt;userId&lt;/code&gt; and write the output value (the user's ID) there.&lt;/p&gt;

&lt;p&gt;It feels as if getting the value from a DB is a side effect.&lt;/p&gt;

&lt;p&gt;The same goes when you decode a JSON string. In &lt;a href="https://pkg.go.dev/encoding/json#example-Unmarshal"&gt;this example&lt;/a&gt;, on Line 4, &lt;code&gt;Unmarshal()&lt;/code&gt; method unpacks the JSON string and writes it to &lt;code&gt;&amp;amp;animals&lt;/code&gt;, the address of &lt;code&gt;animals&lt;/code&gt; variable. And this is a side effect. The return value is again, either an error or &lt;code&gt;nil&lt;/code&gt; — if there &lt;em&gt;is&lt;/em&gt; an error, you simply can't ignore it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jsonBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[
    {"Name": "Platypus", "Order": "Monotremata"},
    {"Name": "Quoll",    "Order": "Dasyuromorphia"}
]`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;animals&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;
&lt;span class="c"&gt;// (4)&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonBlob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>A study of bugs</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Wed, 20 Jul 2022 06:11:34 +0000</pubDate>
      <link>https://dev.to/t0nghe/a-study-of-bugs-lep</link>
      <guid>https://dev.to/t0nghe/a-study-of-bugs-lep</guid>
      <description>&lt;p&gt;I changed the name of my blog to “A study of bugs”.&lt;/p&gt;

&lt;p&gt;It had been called “my notes”. But that feels quite formal. It suggests there are concrete thoughts presented in them. (Maybe I feel this way because in a zettelkasten system, each note is supposed to be a self-contained bit of thought.)&lt;/p&gt;

&lt;p&gt;In programming and debugging, I see bugs and solve them. Each bug is bewildering in its own way. Solving them problems they pose is usually  a haphazard fumbling. &lt;/p&gt;

&lt;p&gt;All I’m saying is I like this new name a lot. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Emulating Python's zip() and zip_longest() in JavaScript</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Tue, 21 Sep 2021 22:28:24 +0000</pubDate>
      <link>https://dev.to/t0nghe/emulating-python-s-zip-and-ziplongest-in-javascript-3den</link>
      <guid>https://dev.to/t0nghe/emulating-python-s-zip-and-ziplongest-in-javascript-3den</guid>
      <description>&lt;p&gt;This is essentially how you emulate the way Python's &lt;code&gt;zip()&lt;/code&gt; function works using JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// result&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What makes this possible is the fact that JavaScript array methods — &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;forEach()&lt;/code&gt; and even &lt;code&gt;filter()&lt;/code&gt; — take up to three arguments (element, index, array) while they iterate through the array. &lt;/p&gt;

&lt;p&gt;In which &lt;code&gt;element&lt;/code&gt; is the element that the iterator points to at each step, &lt;code&gt;index&lt;/code&gt; is the index of this item in the original array. And it's worth noting the third argument is the original array.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;map()&lt;/code&gt; method of the JavaScript array is more flexible than &lt;code&gt;zip()&lt;/code&gt;, we can do more stuff to the iterated item or the array. But if you want to do anything with &lt;code&gt;array&lt;/code&gt;, remember the original array changes accordingly. In this case, &lt;code&gt;a&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]]}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Result&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Result&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, integers 2, 6 and 10 are pushed to the end of the array. &lt;/p&gt;




&lt;p&gt;Python provides a &lt;code&gt;zip_longest()&lt;/code&gt; function in &lt;code&gt;itertools&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;While &lt;code&gt;zip()&lt;/code&gt; cuts off longer lists to fit the shortest, &lt;code&gt;zip_longest()&lt;/code&gt; stretches shorter lists to match the longest. Empty slots in shorter lists are filled with a given value. By default this &lt;code&gt;fillvalue&lt;/code&gt; is &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is how this function works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;itertools&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip_longest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# Result
&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below I try to emulate this function in JavaScript.&lt;/p&gt;

&lt;p&gt;First let's take a look at line 👀. Notably, In order to take indefinite number of arguments, I'm using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax"&gt;ellipsis operator&lt;/a&gt;. Unlike unpacking a list using the &lt;a href="https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists"&gt;star operator (*) in Python&lt;/a&gt;, using something like &lt;code&gt;...args, fillvalue=null&lt;/code&gt; will raise an error. So I have to use a pair of square brackets to allow for a &lt;code&gt;fillvalue&lt;/code&gt; argument. (Let's give it a duck.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zipLongest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;fillvalue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="err"&gt;👀&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;argArray&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;argArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ithColumn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;argArray&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;argArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="err"&gt;👓&lt;/span&gt;
              &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;fillvalue&lt;/span&gt;
              &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;argArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ithColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipLongest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;fillvalue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Result&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="err"&gt;🙄&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duck&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's move to line 👓. Empty slots in the JavaScript array are considered &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;undefined&lt;/code&gt; and other falsy values, eg empty strings and 0, all evaluates to &lt;code&gt;false&lt;/code&gt;. This will confused this ternary conditional. As a result we will get &lt;code&gt;[ -1, undefined, 'd' ]&lt;/code&gt; on line 🙄. &lt;/p&gt;

&lt;p&gt;A better way is to check the type of item as we iterate. However, a wrong way to do it is using &lt;code&gt;typeof nonExistentValue === undefined&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Although the &lt;code&gt;nonExistentValue&lt;/code&gt; is indeed not defined, &lt;code&gt;typeof&lt;/code&gt; returns &lt;code&gt;"undefined"&lt;/code&gt;, which is a string. And this string is a string. It is by no means equal to the reserved word for non-existent things. Thus the condition we used on line 👓.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Don't Edit Hosts File With Nano on a Mac</title>
      <dc:creator>Tonghe Wang</dc:creator>
      <pubDate>Tue, 21 Sep 2021 22:23:20 +0000</pubDate>
      <link>https://dev.to/t0nghe/don-t-edit-hosts-file-with-nano-on-a-mac-17mf</link>
      <guid>https://dev.to/t0nghe/don-t-edit-hosts-file-with-nano-on-a-mac-17mf</guid>
      <description>&lt;p&gt;TLDR: If you are using a Mac, don't edit your hosts file with Nano and save it in Mac format. It will cause bizarre bugs in places you won't expect. If you are seeing bugs on a Mac with errors saying localhost is missing, try opening the hosts file and save it with Unix line ending.&lt;/p&gt;




&lt;p&gt;I learned this while working on a React Native project, where Expo's development server just wouldn't start up. After a long and patient wait, an elaborate error message showed up. In which the most eye-catching line said: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;RangeError [ERR_SOCKET_BAD_PORT]: options.port should be &amp;gt;= 0 and &amp;lt; 65536. Received 65536.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After multiple trials, including upgrading Node.js to the latest version and upgrading Catalina to Big Sur, this bug persisted.&lt;/p&gt;

&lt;p&gt;Taking a second look at the error message, the package in question was actually &lt;code&gt;freeport-async&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Googling around did help. Although I didn't see anyone sharing a bug quite like mine, some on the internet did share how they solved a bug by editing the source code of &lt;code&gt;freeport-async&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What &lt;a href="https://github.com/expo/freeport-async"&gt;freeport-async&lt;/a&gt; does is check available ports on your localhost within a specified range. It has &lt;code&gt;async&lt;/code&gt; in its name because it returns a promise.&lt;/p&gt;

&lt;p&gt;I didn't actually need it to find an available port on my machine. I wasn't running many servers anyway. So I commented out almost all the code. And asked &lt;code&gt;freePortAsync()&lt;/code&gt; to return a determinate number 19000, in consistency with 19xxx ports used by Expo. It worked.&lt;/p&gt;

&lt;p&gt;It was certainly a dirty hack. But I still felt quite good about myself. &lt;/p&gt;

&lt;p&gt;However, there were some quirks. While I could preview my app in an iOS simulator, I couldn't see it in a web browser.&lt;/p&gt;

&lt;p&gt;Then a few bizarre error messages flashed back in my mind. Before this, whenever I created new React projects, although the development server started up fine, I couldn't reach it at &lt;code&gt;localhost:3000&lt;/code&gt;. Weird though, &lt;code&gt;127.0.0.1:3000&lt;/code&gt; would always work.&lt;/p&gt;

&lt;p&gt;Looking through my notes, Node.js once also gave an error messages related to &lt;code&gt;localhost&lt;/code&gt;, saying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getaddrinfo ENOTFOUND localhost
Error: getaddrinfo ENOTFOUND localhost
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was absolutely baffled because I've checked — and at times edited — the &lt;code&gt;hosts&lt;/code&gt; file on my Mac a million times. There had always been an entry for &lt;code&gt;localhost&lt;/code&gt; pointing to &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Until I found &lt;a href="https://apple.stackexchange.com/a/308069"&gt;this comment&lt;/a&gt; by &lt;a href="https://apple.stackexchange.com/users/197799/satya"&gt;Satya&lt;/a&gt; in a quarter of StackExchange for Apple users:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After living with this for a long time, I figured out (by checking from the Sublime editor) that the issue with my /etc/hosts file was that the "Line Endings" on the file were set to "Mac OS". When I changed the line endings to "Unix", I am able to ping localhost in the terminal and stuff's working as expected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every time I needed to edit something in a protected directory, out of convenience, I had always used &lt;code&gt;sudo nano &amp;lt;filename&amp;gt;&lt;/code&gt;. When saving the file, I'd always choose &lt;code&gt;Mac Format&lt;/code&gt; — Why wouldn't I? I'm using a Mac after all.&lt;/p&gt;

&lt;p&gt;I opened up &lt;code&gt;hosts&lt;/code&gt; file and saved it with Unix-style LF line ending. Restarted the computer. All the bugs mentioned above just disappeared! &lt;/p&gt;

&lt;p&gt;Googling keywords “React Native” or “Expo” didn't give me a solution because it was not a problem of React Native or Expo. Besides, who would've expected Mac OS to be tripped up by a config file saved with Mac line ending? &lt;/p&gt;

</description>
      <category>hosts</category>
      <category>mac</category>
      <category>webdev</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
