Compare commits

..

No commits in common. "3a3f98d8fed27c046f352491108ff542781c6785" and "d83fbafa1164c670fa282d12ea7f052c6832eda6" have entirely different histories.

7 changed files with 5 additions and 448 deletions

2
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "themes/hello-friend-ng"]
path = themes/hello-friend-ng
url = git@git.kaholaz.net:kaholaz/hello-friend-ng.git
url = git@github.com:Kaholaz/hugo-theme-hello-friend-ng.git

View file

@ -1,14 +1,8 @@
---
title: "Om meg"
title: "About"
date: 2023-12-26T14:12:12+01:00
draft: false
---
Hei!
Jeg så hyggelig at du tok deg tid til å se gjennom min lille nettside! Her
skriver jeg om det som faller meg inn. Mesteparten av tiden handler det om
teknologi, erfaringer eller kuriositeter.
Om du er interessert i å ta kontakt med meg kan jeg nås ved epost på <a
href="mailto:vkbugge@hotmail.com">vkbugge@hotmail.com</a>.

View file

@ -1,313 +0,0 @@
---
title: "Eierskap: Ikke bare en \"Rust-greie\""
date: 2023-12-29T18:01:35+0100
draft: false
toc: false
images:
tags:
- rust
- systemprogrammering
---
Jeg kom nylig over et artig eksempel av erierskap i praksis.
```c
#include <stdio.h>
char* example() {
return "Hello world!";
}
int main() {
printf("%s\n", example());
return 0;
}
```
Her har har vi funksjonen `example` som returnerer `"Hello world!"`. Denne
verdien printes i funksjonen `main`.
```bash
$ clang -O3 example.c
$ ./a.out
Hello world!
```
Kult! Programmet printer "Hello world!" :) Hva om vi gjør en liten
modifikasjon?
```c
#include <stdio.h>
#include <string.h>
char* example() {
char out[13] = "Hello ";
return strcat(out, "world!");
}
int main() {
printf("%s\n", example());
return 1;
}
```
Her har vi bare erstattet `"Hello world!"` med `strcat("Hello ", "world!")`.
Det burde vel ikke gjøre noen forskjell.
```bash
$ clang -O3 example.c
$ ./a.out
d␃Z
```
Hv..a? Programmet printer bare masse rare tegn?!
## Hva skjedde?
Som mange andre rare observasjoner innen programmering, er årsaken til dette
resultatet hvordan programmet håndterer minne. I C er en
[streng](https://en.wikipedia.org/wiki/String_(computer_science)) en
[tabell](https://en.wikipedia.org/wiki/Array_(data_structure)) med bokstaver
som avsluttes med en [nullbyte](https://en.wikipedia.org/wiki/Null_character).
Om en streng tilordnes en variabel, er verdien til varabelen en
[peker](https://en.wikipedia.org/wiki/Pointer_(computer_programming)) til den
første bokstaven i strengen.
Okay, så hva er det som skjer? Når man oppretter en ny variabel, lagres
variabelverdien øverst i den nåværende
[kallstakken](https://en.wikipedia.org/wiki/Call_stack). Denne verdien kan
enten være hele verdien som lagres (hvis verdien f.eks. er en int), eller en
peker til hvor i minnet verdien til variabelen faktisk ligger.
Hvis man oppretter en tabell inni en funksjon, opprettes minnet som er
nødvendig for denne tabellen øverst i den nåværende kallstakken. Verdien til
pekeren er minneadressen til det første elementet av tabellen. Hvis man
returnerer fra denne funksjonen, deallokeres tabellen sammen med resten av
kallstakken. Hvis man returnerer en peker til en tabell som er lagret i
stakken, peker denne pekeren nå på udefinert minne. Det er dette som skjer i
eksempel nummer 2.
Okay, men hva er da greia med det første eksempelet? Hvorfor fungerer dette som
forventet? Vi kan få et lite hint om vi printer ut adressene til de ulike
variablene :)
```c
#include <stdio.h>
int main() {
char string[13] = "Hello world!";
printf("Streng-addresse: %p\n", string);
printf("Peker-addresse: %p\n", &string);
return 0;
}
// Resultat:
// Streng-addresse: 0x7ffc98bf8730
// Peker-addresse: 0x7ffc98bf8730
```
Pekeren og strengen er på samme adresse. Strengen ble allokert i stakken.
```c
#include <stdio.h>
int main() {
char* string = "Hello world!";
printf("Streng-addresse: %p\n", string);
printf("Peker-addresse: %p\n", &string);
return 0;
}
// Resultat
// Streng-addresse: 0x595c41bd1004
// Peker-addresse: 0x7ffeed215580
```
Pekeren og strengen er på helt forskjellige steder i minnet! I dette tilfellet
er det en illusjon at strengen opprettes i stakken. Selv om strengen først
tilordnes i funksjonen, allokeres strengen ved programstart i en minnesegmentet
[data](https://en.wikipedia.org/wiki/Data_segment). Minnet forblir tilgjengelig
til programmet avsluttes.
## Hva har dette med eierskap å gjøre?
[Eierskap](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) er et
konsept i [Rust](https://www.rust-lang.org/) som baserer seg på at alle verdier
kun har én eier. Eieren er ansvarlig for frigjøringen av minnet. Eierskapet kan
overføres eller lånes bort. Om eierskapet lånes bort, beholder den opprinnelige
eieren pliktene som kommer med eierskapet etter at utlånet er omme. Om
eierskapet gis bort, overføres eierpliktene til den nye eieren. Til gjengjeld
kan den opprinnelige eieren ikke lenger akksessere verdien. Verdier kan
nemmelig kun aksesseres dersom man enten eier verdien eller om verdien er lånt
bort til deg. På denne måten unngår man mulighetene for vanlige minnefeil som
[minnelekasjer](https://en.wikipedia.org/wiki/Memory_leak), [hengende
pekere](https://en.wikipedia.org/wiki/Dangling_pointer) og
[dataløp](https://en.wikipedia.org/wiki/Race_condition).
Eksempelet vi så på i stad, var et eksempel på en hengende peker. Vi prøver å
lese fra en minneadresse som ikke lenger er gyldig. La oss prøve å gjennskape
det første eksempelet i Rust.
```rust
fn example() -> &str {
return "Hello world!";
}
fn main() {
println!("{}", example());
}
```
Funksjonen example returnerer nå en referanse til en streng. Hvis vi prøver å
kompilere dette får vi derimot en feilmelding.
```rust
error[E0106]: missing lifetime specifier
--> src/main.rs:1:17
|
1 | fn example() -> &str {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
|
1 | fn example() -> &'static str {
| +++++++
For more information about this error, try `rustc --explain E0106`.
```
Rust gir oss faktisk en gangske forståelig feilmelding! Referanser er navnet på
de lånte verdiene jeg snakket om tidligere. Disse trenger et såkalt "lifetime".
Dette er en verdi som forteller kompilatoren hvor lenge en referanse maksimalt
kan "leve", altså hvor lenge eieren til variabelen har tenkt å holde på den.
Lifetimes er i de aller fleste tilfeller definert implisitt, men noen ganger må
vi spesifisere dem selv. På denne måten kan man unngå situasjoner der man har
en referanse til en verdi som ikke lenger finnes, eller på andre ord: At
variabellånet varer lengre enn det orginale eierskapet av variabelen.
Om du husker tilbake på eksempelet vi prøver å gjenskape, var strengen lagret i
datasegmentet av minnet. Dette er en statisk minneregion som allokeres ved
programstart og deallokeres ved programslutt. Referanser til denne
minneregionen kan markeres med lifetimen `static`.
```rust
fn example() -> &'static str {
return "Hello world!";
}
fn main() {
println!("{}", example());
}
```
Dette programet kompilerer og kjører uten problemer! Det printer det samme som
det første eksempelet vårt!
```bash
$ cargo run --release
Compiling stack-string v0.1.0 (/home/kaholaz/code/rust/stack-string)
Finished release [optimized] target(s) in 0.18s
Running `target/release/stack-string`
Hello world!
```
La oss prøve oss på eksempel nummer to!
```rust
fn example() -> &'static str {
return "Hello " + "world!";
}
fn main() {
println!("{}", example());
}
```
Å nei :( Vi får igjen en feilmelding når vi prøver å kompilere...
```rust
error[E0369]: cannot add `&str` to `&str`
--> src/main.rs:2:21
|
2 | return "Hello " + "world!";
| -------- ^ -------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
|
= note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
|
2 | return "Hello ".to_owned() + "world!";
| +++++++++++
For more information about this error, try `rustc --explain E0369`.
```
I Rust finnes det flere typer som representerer strenger. Vi har vært innom
`&str`, men nå støter vi på en ny en: `String`. Mens `&str` representerer en streng
som vi låner, representerer `String` en streng vi eier. Det betyr at vi nå har
ansvaret for minnet strengen opptar, og at minnet automatisk blir deallokert
for oss når vi returnerer fra den nåværende funksjonen. For at det ikke skal
skje, må vi overføre eierskapet. En måte å gjøre dette på, er ved å returnere
verdien. Når vi har implementert forslaget fra kompilatoren og endret
returtypen ser programmet vårt slikt ut:
```rust
fn example() -> String {
return "Hello ".to_owned() + "world!";
}
fn main() {
println!("{}", example());
}
```
Dette kompilerer og kjører uten problemer!
## Kan dette overføres til C?
Vi har sett at man kan unngå å gjøre enkle feil når det kommer til
minnebehandling ved å tenkte på eierskap i Rust. Hvordan kan vi bruke dette til
å fikse feilen vi hadde i C programmet vårt?
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* example() {
char* out = malloc(13);
strcpy(out, "Hello ");
return strcat(out, "world!");
}
int main() {
char* ex = example();
printf("%s\n", ex);
free(ex);
return 0;
}
```
Her må vi fohåndsallokere plassen til strengen i
[heapen](https://en.wikipedia.org/wiki/Manual_memory_management), samt passe på
at vi frigjør minnet etter at vi er ferdig med det. Legg merke til at selv om
ikke må tenke på eierskap, oppstår de samme problemene som Rust-kompilatoren
advarte oss om. Hvis man returnerer en peker til en verdi som kanskje
forsvinner før pekeren gjør det, kan man få en hengende peker. Hvis man ikke
tenker på hvem som har ansvaret for å deallokere minnet til verdier, kan man få
minnelekasjer.
I motsetning til i Rust, gjør ikke C noen forskjell på pekere som vi låner og
pekere vi eier. Det betyr at det kan være uklarheter når det kommer til om det
er vårt ansvar å frigjøre minnet pekeren peker til.
## Konklusjon
Selv om C ikke har et innebygd system for eierskap og livstider som Rust, betyr
det ikke at konseptet ikke har noen verdi når det kommer til utvikling av
programmer skrevet i C. C gir deg frihet til å programmere på lavt nivå. Til
gjengjeld krever det at man gjør en bevisst innsats for å unngå vanlige feil
ved håndtering av minne. Personlig har min forståelese og bevisthet knyttet til
minne blitt bedre etter at jeg nå har vasset litt rundt i Rustverdenen. Jeg
håper derfor at du (om du allerede ikke har gjort det) tar sjansen og dupper
tåa di nedi du også! Kanskje det lønner seg for deg og?

View file

@ -1,119 +0,0 @@
---
title: "Hugo"
date: 2023-12-26T16:16:07+01:00
draft: false
toc: false
images:
tags:
- web
- privat
---
Nå er bloggen gjennoppstått! Denne gangen med hjelp av [Hugo](https://gohugo.io/) :)
## Hva er Hugo?
Hugo er en statisk side-generator. Du skriver innlegg i markdown, også rendres
disse til HTML. Når du har HTML-en, kan du egentlig gjøre det du vil med den:
Servere den fra en webserver, redigere den i VScode, eller sende den til
kompisen din og si at du kan lage nettsider.
## Motivasjon
Den forrige bloggen min var laget med [Wordpress](https://wordpress.com/), en
grafisk nettsidebygger som er laget med PHP og MySQL. Programmet kan brukes til
å lage alt fra blogger til nettbutikker. For mitt bruk, fungerte det egentlig
ganske greit, men det var et par punkter gjorde at det ikke var helt optimalt.
En ting jeg ikke likte med Wordpress, var fokuset på utseende. Programmet er
designet slik at man lett skal kunne plassere ulike elementer i et
brukerdefinert layout. Det kan være kjekt om man:
1. Ønsker å definere layout selv
1. Ikke kan HTML
For meg gjelder ingen av delene. Jeg ønsker først og fremst å skrive tekster,
og i de tilfellene jeg bry meg om layout, klarer jeg fint å skrive litt HTML.
Det at at Wordpress er designet for å gjøre det lett å endre layout, gjør det
krunglete å skrive innlegg. Hvis jeg for eksempel skal skrive et innlegg med to
overskrifter, er det 4 elementer som må opprettes (et for hver overskrift og
hver tekst). Dette tar vekk fokuset fra skrivingen.
Med Hugo derimot, er fokuset rettet mot skrivingen. Når man skal lage et nytt
innlegg, kan man få Hugo til å generere en ny markdownfil for deg.
```bash
hugo new content posts/hugo
```
Nå har jeg en fil ny fil (`content/posts/hugo.md`). Denne kan man fint begynne
å skrive i og endre på med ditt yndlingstekstredigeringsprogram. Personlig
bruker jeg [Neovim](https://neovim.io/). Det at jeg nå kan klare meg uten
datamusa når jeg lager et nytt innlegg, ser jeg på som en veldig positiv ting.
En annen fordel med at alle innleggene mine er markdown filer, er at det er
ekstremt kjekt å jobbe med tekstfiler! Om jeg skal endre på innholdet, kan jeg
bruke Neovim. Om jeg skal finne ut av når jeg skrev om en spesifikk ting, kan
jeg bruke [ripgrep](https://github.com/BurntSushi/ripgrep). Om jeg har lyst til
å slutte å bruke Hugo kan jeg også det, fordi det kun er tekst!
## Fremgangsmåte
Det å sette opp bloggen var egentlig veldig lett! Slik var fremgangsmåten:
### Sett opp Hugo
1. Installer Hugo.
```bash
sudo snap install hugo
```
1. Start et nytt prosjekt.
```bash
hugo new site blog
cd blog
git init
```
1. Last ned et tema.
```bash
git add submodule https://github.com/rhazdon/hugo-theme-hello-friend-ng themes/hello-friend-ng
```
1. Fiks `hugo.toml` i henhold til [dokumentasjonen](https://github.com/rhazdon/hugo-theme-hello-friend-ng).
1. Enjoy!
### Deployment
Jeg er så heldig å ha tilgang til en server der jeg kan servere hva enn jeg
måtte ønske! Det gjør jobben veldig lett :) På serveren har jeg en mappe
(`/var/www/kaholaz.net/`), der jeg putter ferdiggenerert HTML. Får å gjøre
denne forflytningen lettvint, har jeg laget et kort skript for å generere HTML
og flytte det over til serveren.
```sh
hugo || exit
rsync public/ vsbugge@navi.samfundet.no:/var/www/kaholaz.net/ -r --delete -P
```
Når dette er på plass, trenger vi bare et søtt lite Apache-config for å gjøre
susen.
```xml
<VirtualHost *:80>
ServerName kaholaz.net
DocumentRoot /var/www/kaholaz.net/
<Location />
Options -Indexes
</Location>
ErrorDocument 404 /404.html
</VirtualHost>
```
## Konklusjon
Jeg tror dette er en veldig flott løsning for en personlig blogg. Jeg kommer
til å tilgjegeliggjøre kildekoden på [min
GitHub](git@github.com:Kaholaz/hugo-blog.git), og fortsette å oppdatere bloggen
gjenvlig. Det er en del ting å fikse, slik som tagger og innleggstyper. Alt i
alt vil jeg anbefale Hugo om man ønsker en no-nonsense måte å skrive en blogg
på!

View file

@ -1,5 +1,2 @@
if [ -n "$1" ]; then
sed -i -E 's/(draft: )true/\1false/; s/(date: ).*/\1'$(date '+%Y-%m-%dT%T%z')'/' content/posts/$1.md
fi
hugo || exit
rsync public/ vsbugge@navi.samfundet.no:/var/www/kaholaz.net/ -r --delete -P

View file

@ -2,9 +2,7 @@ baseurl = "https://kaholaz.net"
title = "Sebastian Bugge"
languageCode = "nb-NO"
theme = "hello-friend-ng"
[pagination]
pagerSize = 10
paginate = 10
PygmentsCodeFences = true
PygmentsStyle = "monokai"
@ -44,7 +42,7 @@ disableHugoGeneratorInject = false
dateformNumTime = "2006-01-02 15:04"
# Subtitle for home
# homeSubtitle = "problemløser, tenker, student"
homeSubtitle = "problemløser, tenker, student"
# Set disableReadOtherPosts to true in order to hide the links to other posts.
disableReadOtherPosts = false

@ -1 +1 @@
Subproject commit 6716ce4a6c901483e8cd32b1aa3f8cda61c9db15
Subproject commit 1325761a870c6a451b1a39aeb1c560b604605cf8