diff --git a/astro.config.mjs b/astro.config.mjs index 715c0e7..5ba5b29 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -4,5 +4,13 @@ import tailwind from "@astrojs/tailwind"; // https://astro.build/config export default defineConfig({ - integrations: [tailwind()] + integrations: [tailwind()], + markdown: { + shikiConfig: { + themes: { + light: "catppuccin-latte", + dark: "github-dark" + }, + }, + }, }); diff --git a/package.json b/package.json index 0f80d7a..019defa 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,8 @@ "astro": "^4.6.1", "tailwindcss": "^3.4.3", "typescript": "^5.4.5" + }, + "devDependencies": { + "@shikijs/transformers": "^1.6.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df7b4d4..78d02b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,10 @@ importers: typescript: specifier: ^5.4.5 version: 5.4.5 + devDependencies: + '@shikijs/transformers': + specifier: ^1.6.0 + version: 1.6.0 packages: @@ -588,6 +592,12 @@ packages: '@shikijs/core@1.3.0': resolution: {integrity: sha512-7fedsBfuILDTBmrYZNFI8B6ATTxhQAasUHllHmjvSZPnoq4bULWoTpHwmuQvZ8Aq03/tAa2IGo6RXqWtHdWaCA==} + '@shikijs/core@1.6.0': + resolution: {integrity: sha512-NIEAi5U5R7BLkbW1pG/ZKu3eb1lzc3/+jD0lFsuxMT7zjaf9bbNwdNyMr7zh/Zl8EXQtQ+MYBAt5G+JLu+5DlA==} + + '@shikijs/transformers@1.6.0': + resolution: {integrity: sha512-qGfHe1ECiqfE2STPWvfogIj/9Q0SK+MCRJdoITkW7AmFuB7DmbFnBT2US84+zklJOB51MzNO8RUXZiauWssJlQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1833,6 +1843,9 @@ packages: shiki@1.3.0: resolution: {integrity: sha512-9aNdQy/etMXctnPzsje1h1XIGm9YfRcSksKOGqZWXA/qP9G18/8fpz5Bjpma8bOgz3tqIpjERAd6/lLjFyzoww==} + shiki@1.6.0: + resolution: {integrity: sha512-P31ROeXcVgW/k3Z+vUUErcxoTah7ZRaimctOpzGuqAntqnnSmx1HOsvnbAB8Z2qfXPRhw61yptAzCsuKOhTHwQ==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -2746,6 +2759,12 @@ snapshots: '@shikijs/core@1.3.0': {} + '@shikijs/core@1.6.0': {} + + '@shikijs/transformers@1.6.0': + dependencies: + shiki: 1.6.0 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.24.4 @@ -4383,6 +4402,10 @@ snapshots: dependencies: '@shikijs/core': 1.3.0 + shiki@1.6.0: + dependencies: + '@shikijs/core': 1.6.0 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} diff --git a/public/blog.css b/public/blog.css index 033c927..46ac343 100644 --- a/public/blog.css +++ b/public/blog.css @@ -1,11 +1,32 @@ - -#blog code { +:not(pre)>code { font-family: "Iosevka Fixed Web", Iosevka, monospace; - border: solid 1px var(--c-on-bg); + border: solid 1px var(--c-border-2); padding: 0 0.25rem; border-radius: 0.25rem; } +pre.astro-code { + padding: 1rem; + border-radius: 0.5rem; + border: solid 1px var(--c-border-1); + font-size: 0.9rem; +} + +pre.astro-code>code { + counter-reset: step; + counter-increment: step 0; +} + +pre.astro-code>code .line::before { + content: counter(step); + counter-increment: step; + width: 1rem; + margin-right: 1.5rem; + display: inline-block; + text-align: right; + color: rgba(115, 138, 148, .4) +} + #blog p { margin: 1rem 0; } @@ -27,3 +48,16 @@ text-decoration: underline; color: #3b82f6; } + +@media (prefers-color-scheme: dark) { + + .astro-code, + .astro-code span { + color: var(--shiki-dark) !important; + background-color: var(--shiki-dark-bg) !important; + /* Optional, if you also want font styles */ + font-style: var(--shiki-dark-font-style) !important; + font-weight: var(--shiki-dark-font-weight) !important; + text-decoration: var(--shiki-dark-text-decoration) !important; + } +} \ No newline at end of file diff --git a/public/global.css b/public/global.css index 6e662e3..4f14e1d 100644 --- a/public/global.css +++ b/public/global.css @@ -31,6 +31,8 @@ --c-on-bg: #dedede; --c-bg-2: #18181b; + --c-border-1: transparent; + --c-border-2: #606060; } @media (prefers-color-scheme: light) { @@ -39,6 +41,8 @@ --c-on-bg: #101010; --c-bg-2: white; + --c-border-1: #aaaaaa; + --c-border-2: #aaaaaa; } } diff --git a/src/pages/blog/go-1.md b/src/pages/blog/go-1.md new file mode 100644 index 0000000..1e2233d --- /dev/null +++ b/src/pages/blog/go-1.md @@ -0,0 +1,162 @@ +--- +layout: ../../layouts/BlogLayout.astro +title: Golang first impressions +description: First thoughts after using a little bit of Golang +pubDate: "2024-05-25" +tags: ["programming", "golang", "rust", "short"] +image: + url: "" + alt: "" + caption: "" +--- + +I've been trying out Golang for a few days, and here are some thoughts +I have about it. + +And by a few days I mean that I've solved AoC until day 11 (I think), +and I'm writing a game backend that communicates via JSON/WebSockets +to a web frontend. + + +## Irrelevant background + +I don't remember where did I hear about Golang first. But I clearly +remember that my first opinion of it was heavily influenced by fasterthanlime +posts about it. I think I discovered his page with his "I want off Mr. Golang's +wild ride" and "Lies we tell to ourselves to keep using Golang" posts. + +So, I had a negative impression about it for some time. And at the time I +was felling in love with Rust, which Amos uses as a comparison point, +so all the arguments made sense, and I did what any reasonable person on the +internet would do: I made his arguments mine :) + +Then, another tech-fluencer I follow began to talk about Golang. ThePrimeagen. +And apparently he liked Golang a lot. He was (and I think still is at the +time of writing) learning +Golang, and was happy to try it out. So I did what any reasonable person on +the internet would do: I made his opinions mine :) + +And so, I decided to try out Golang, coming from having learned a lot of Rust. + + +## A nicer C + gc + +My very first impression was that it felt a lot like C. Very imperative code, +very simple, very minimalist. You can't even do something like `"hello".length`, +you do `len("hello")`, in a very C-style. However, you don't have to manually +manage all your memory, since Golang is garbage collected. So, it feels like a +nicer C. + + +## Confusion with references + +I think that Rust messed up with the way that I think about +references/parameters/pass-by-value/pass-by-reference. + +First, in Java and JS I got used that anything that is not a primitive +datatype is passed by reference. Since neither of these use pointers, that's +reasonable. + +Then, in Rust, you define instead ownership, lifetimes and references. So, I +got used to: + +```rust +fn test_function<'a>( + a: Type, + b: mut Type, + c: &Type, + d: &mut Type, + e: &'a Type, + f: &'a mut Type, +) { + // ... +} +``` + +Which are, off the top of my head: + +- a: Take ownership of `Type` +- b: Take ownership of a mutable `Type` +- c: A reference to `Type` +- d: A mutable reference to `Type` +- e: A reference to `Type` with lifetime `'a` +- f: A mutable reference to `Type` with lifetime `'a` + +I got used to pass-by-refernce, in one way or another. + +So, I came to Golang expecting the same. Primitive types are passed by value, +complex types are passed by reference. But apparently they aren't, which had +me scratching my head for many hours. + +I had a function that took a struct, modified some values, and returned. + +```go +// Some hypothetical code +type Node struct { + Value string + Visited bool +} + +func mark_as_visited(node Node) { + // ... + node.Visited = true + // ... +} +``` + +Apparently, this will create a copy of `Node` instead of mutating the parameter. +So Golang doesn't have automaty pass-by-reference, only pass-by-value. Which +mimics the way C works, but in my limited experience with C I was always using +pointers due to `malloc` and friends, so I never noticed. Skill issue. + +But still, for a garbage collected language, I was expecting it to behave like +other garbage collected languages. (And now I wonder if Go is garbage collected, +and you can't do pointer arithmetic, why do you have access to pointers?) + + + +## if err != nil + +I wish Go had some amount of syntax for error handling. `if err != nil` feels +verbose, but it's not bad. What I'm confused about still is why it's all +`error`, instead of having different error types? I guess I got used to Rust. + +Still, errors as values are the best way to do error handling. + +## nil + +It's 2024 and we still have `nil` pointer exceptions. I think it's a huge +mistep to not have some form of nullable types. Something like `int?` that +clearly communicates that the value can be `nil`, and more importantly, +that forces you to explicitly check for it. Kotlin, Rust, Zig, Nim and +almost every modern language have it. + +And being relatively "low-level" or having a runtime penalty is not an excuse +because a) Go is not "low-level" b) Go ships a gc and runtime with every binary +c) Zig is "low-level" and still has nullable types. + + +## zero values + +Altough zero values have not caused problems for me (yet), I can definitely see +how they are bad. Just having a struct that contains a pointer to other struct +can potentially cause a NPE, and the compiler doesn't do anything about it. + +Yes, it's a skill issue to not check in every single place structs are used. +And by that logic, it's a skill issue to not program in punch cards and use +modern languages. smh. + + +## devtools + +The devtools are (as far as my limited used goes) really, really good. The +language server is fast, I love the fast, opinionated, on save code formatter +(better than rust analyzer & cargo fmt) and the package manager is good. + +## conclusions + +So in conclusion, I'm still learning Go. I'm not at the level that +the things that Amos complains about are problems for me. But insofar, the +language itself is, to me, inferior to Rust. Still good, but not as good +as Rust in every aspect. + diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index 2463e0a..9fb5f67 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -17,5 +17,10 @@ import BlogLayout from "../../layouts/BlogLayout.astro"; The responsible stack +
  • + + Golang first impressions + +