Compare commits
71 Commits
develop-ru
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 45922b7faf | |||
| a0b8852a9a | |||
| 36689a9a0c | |||
| 3cde3573ba | |||
| 45d4f40343 | |||
| 872034807d | |||
| 5420bd2406 | |||
| 9d3017dd27 | |||
| f3d68bdaac | |||
| 11c1775ab5 | |||
| 23ae5628de | |||
| a4b94a467b | |||
| df6aa422e9 | |||
| f3a55df7df | |||
| e8b59cc3ff | |||
| 2ed570cae5 | |||
| 9ed4547da7 | |||
| a76daa7831 | |||
| 4f5fb3f0f6 | |||
| fb63f75f87 | |||
| 9516c876ac | |||
| 3714f85d86 | |||
| e253970e14 | |||
| a50a5d398f | |||
| 308997c63b | |||
| 80fdf0ef6f | |||
| e3e7b0c117 | |||
| 63d54fe72c | |||
| 9b48faf931 | |||
| 72620c3b20 | |||
| 2b8289561e | |||
| f244573931 | |||
| 40ad19b917 | |||
| c866be02ee | |||
| aaf27a7b9b | |||
| 8bc8805cd5 | |||
| 7e33876581 | |||
| 6a1a7b3c2b | |||
| 83b8604597 | |||
| c81d45a327 | |||
| eed64163b0 | |||
| 64fc1dfdb9 | |||
| f984a9cc5d | |||
| 304b3c0e3c | |||
| 786654bd41 | |||
| 2eb94bdde5 | |||
| 7702a4d2da | |||
| 4695cee053 | |||
| c8b000b1e7 | |||
| a70e183c2d | |||
| d8dd7bc94d | |||
| 2cf7d0e223 | |||
| 1d244f907d | |||
| 97620e6759 | |||
| ce2b4fc634 | |||
| 09d3b4e901 | |||
| f2b98ae01d | |||
| 87d2f58e9f | |||
| 35ff7a668d | |||
| e59ee40066 | |||
| 3a111c71ed | |||
| e83d1e9fce | |||
| f43576cab8 | |||
|
|
0b476cac08 | ||
| 1d99786bac | |||
| 009fa8aa0a | |||
| bed4403b67 | |||
| d2d0947fbe | |||
| 8c8b465fa3 | |||
| 628adddb60 | |||
|
|
f52068b291 |
53
.eleventy.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
|
||||
|
||||
module.exports = function(eleventyConfig) {
|
||||
eleventyConfig.addPassthroughCopy("public");
|
||||
eleventyConfig.addPlugin(syntaxHighlight);
|
||||
|
||||
const markdownIt = require("markdown-it");
|
||||
|
||||
const md = markdownIt({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
|
||||
eleventyConfig.setLibrary("md", md);
|
||||
|
||||
md.use(require("markdown-it-toc-done-right"))
|
||||
md.use(require("markdown-it-attrs"))
|
||||
md.use(require("markdown-it-imsize"))
|
||||
md.use(require("markdown-it-sub"))
|
||||
md.use(require("markdown-it-sup"))
|
||||
|
||||
md.use(require("markdown-it-anchor"), {
|
||||
permalink: true,
|
||||
// permalinkSymbol: "#",
|
||||
permalinkBefore: false
|
||||
})
|
||||
|
||||
md.use(require("markdown-it-implicit-figures"), {
|
||||
figcaption: true
|
||||
})
|
||||
|
||||
const markdownItContainer = require("markdown-it-container");
|
||||
|
||||
md.use(markdownItContainer, 'off')
|
||||
md.use(markdownItContainer, 'hero')
|
||||
md.use(markdownItContainer,
|
||||
'spoiler', {
|
||||
validate: function(params) {
|
||||
return params.trim().match(/^spoiler\s+(.*)$/);
|
||||
},
|
||||
|
||||
render: function (tokens, idx) {
|
||||
var m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/);
|
||||
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return '<details><summary>' + md.utils.escapeHtml(m[1]) + '</summary><div class="spoiler-content">\n';
|
||||
} else {
|
||||
return '</div></details>\n';
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
_site
|
||||
package-lock.json
|
||||
2
_includes/footer.pug
Normal file
@@ -0,0 +1,2 @@
|
||||
footer
|
||||
p Vlad Faust © 2020
|
||||
34
_includes/head.pug
Normal file
@@ -0,0 +1,34 @@
|
||||
//- Meta
|
||||
meta(charset='UTF-8')
|
||||
meta(name='viewport', content='width=device-width, initial-scale=1.0')
|
||||
|
||||
<!-- Basics -->
|
||||
title= title ? (titleNoAppend ? title : (title + " | Vlad Faust Blog")) : "Vlad Faust Blog"
|
||||
meta(name='description', content=description || excerpt)
|
||||
meta(name='robots' content="index,follow")
|
||||
meta(name='generator' content='Eleventy')
|
||||
|
||||
<!-- Twitter summary -->
|
||||
meta(name='twitter:card', content='summary')
|
||||
meta(name='twitter:site', content='@vladfaust')
|
||||
meta(name='twitter:creator', content='@vladfaust')
|
||||
meta(name='twitter:url', content='https://vladfaust.com' + page.url)
|
||||
meta(name='twitter:title', content=title)
|
||||
meta(name='twitter:description', content=description || excerpt)
|
||||
meta(name='twitter:image', content=(twitterCover || cover) ? ('https://vladfaust.com' + (twitterCover || cover)) : '')
|
||||
|
||||
<!-- OpenGraph -->
|
||||
meta(property='og:url', content='https://vladfaust.com' + page.url)
|
||||
meta(property='og:type', content=ogType || 'website')
|
||||
meta(property='og:title', content=title)
|
||||
meta(property='og:image', content=(ogCover || cover) ? ('https://vladfaust.com' + (ogCover || cover)) : '')
|
||||
meta(property='og:description', content=description || excerpt)
|
||||
meta(property='og:site_name', content=title)
|
||||
meta(property='og:locale', content='en_GB')
|
||||
meta(property='article:author', content='https://vladfaust.com')
|
||||
|
||||
//- Icons
|
||||
link(rel='icon', href='/public/icon/cap.svg', sizes='any', type='image/svg+xml')
|
||||
|
||||
//- Fonts
|
||||
link(href="https://fonts.googleapis.com/css2?family=Vollkorn:wght@400;700&display=swap", rel="stylesheet")
|
||||
18
_includes/header.pug
Normal file
@@ -0,0 +1,18 @@
|
||||
header
|
||||
a.me(href="/")
|
||||
img(src='/public/img/me.jpg')
|
||||
div.text
|
||||
p
|
||||
| Hello, my name is
|
||||
a(href='/') Vlad Faust
|
||||
| .
|
||||
p.tablet-hide
|
||||
| I'm a passionate developer currently working on
|
||||
a(href='/posts/2020-08-20-the-onyx-programming-language') my own programming language
|
||||
| .
|
||||
p.tablet-hide
|
||||
| You can follow me on
|
||||
a(href='https://twitter.com/vladfaust') Twitter
|
||||
| and
|
||||
a(href='https://github.com/vladfaust') GitHub
|
||||
| and also send nudes to mail at vladfaust.com
|
||||
22
_includes/post.pug
Normal file
@@ -0,0 +1,22 @@
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
include /head.pug
|
||||
|
||||
//- Styles
|
||||
link(rel='stylesheet', href='/public/styles/post.css')
|
||||
link(rel='stylesheet', href='https://unpkg.com/prismjs@1.20.0/themes/prism.css')
|
||||
body
|
||||
include /header.pug
|
||||
|
||||
main.line-numbers
|
||||
h1= title
|
||||
p.meta
|
||||
time.pubtime(datetime=page.date.toISOString())= page.date.toDateString()
|
||||
if location
|
||||
| ,
|
||||
= location
|
||||
hr
|
||||
article!= content
|
||||
|
||||
include /footer.pug
|
||||
65
img/em.svg
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="431.42856"
|
||||
height="431.42856"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="222.88875"
|
||||
inkscape:cy="315.46793"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1301"
|
||||
inkscape:window-height="744"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-156.33296,-310.4668)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.40000001000000002;stroke-miterlimit:4"
|
||||
d="M 0 0 L 0 431.4375 L 431.4375 431.4375 L 431.4375 0 L 0 0 z M 218.3125 65.3125 C 238.31876 65.31275 257.05415 68.30255 274.53125 74.28125 C 292.0079 80.26041 307.18453 89.00226 320.0625 100.5 C 332.93992 111.76819 343.04727 125.69313 350.40625 142.25 C 357.99459 158.80721 361.78094 177.6564 361.78125 198.8125 C 361.78094 215.1397 359.96029 229.51979 356.28125 241.9375 C 352.83156 254.35535 347.87605 264.80406 341.4375 273.3125 C 334.99835 281.82102 327.42567 288.2558 318.6875 292.625 C 309.9488 296.99423 300.29662 299.18751 289.71875 299.1875 C 282.81975 299.18751 276.4675 298.27719 270.71875 296.4375 C 264.96955 294.36789 260.15909 291.26428 256.25 287.125 C 251.1907 290.80436 245.21108 293.56659 238.3125 295.40625 C 231.6435 297.24593 224.63976 298.15626 217.28125 298.15625 C 206.01309 298.15626 195.64692 296.41815 186.21875 292.96875 C 177.02025 289.51938 168.96115 284.36756 162.0625 277.46875 C 155.39358 270.57002 150.24174 262.05575 146.5625 251.9375 C 142.88306 241.58941 141.03116 229.63017 141.03125 216.0625 C 141.03116 204.79461 142.88306 194.20086 146.5625 184.3125 C 150.24174 174.19443 155.50737 165.48384 162.40625 158.125 C 169.53486 150.76647 178.16292 145.01443 188.28125 140.875 C 198.62926 136.50595 210.36091 134.31267 223.46875 134.3125 C 236.11631 134.31267 247.50659 135.33679 257.625 137.40625 C 267.74298 139.47605 275.80209 141.66933 281.78125 143.96875 L 281.78125 250.90625 C 281.78102 257.34515 282.91892 261.81425 285.21875 264.34375 C 287.74806 266.64339 291.07925 267.81254 295.21875 267.8125 C 305.10674 267.81254 312.82447 261.71913 318.34375 249.53125 C 324.09246 237.11353 326.96847 219.40226 326.96875 196.40625 C 326.96847 182.14892 324.43383 168.90673 319.375 156.71875 C 314.54559 144.30113 307.39682 133.62484 297.96875 124.65625 C 288.54019 115.68804 277.06736 108.65306 263.5 103.59375 C 250.16217 98.30491 235.09933 95.68772 218.3125 95.6875 C 201.75529 95.68772 186.46487 98.44995 172.4375 103.96875 C 158.63984 109.48797 146.6806 117.40204 136.5625 127.75 C 126.67417 138.09834 118.84266 150.74032 113.09375 165.6875 C 107.57468 180.63497 104.81244 197.54971 104.8125 216.40625 C 104.81244 236.18281 107.68847 253.55271 113.4375 268.5 C 119.18641 283.21741 127.24551 295.51802 137.59375 305.40625 C 148.17177 315.29449 160.69996 322.75339 175.1875 327.8125 C 189.90474 332.87158 206.21928 335.40623 224.15625 335.40625 C 236.57386 335.40623 247.50897 334.60969 256.9375 333 C 266.59556 331.62023 273.82688 330.33727 278.65625 329.1875 L 282.8125 358.1875 C 280.28272 358.87733 276.95153 359.67386 272.8125 360.59375 C 268.90297 361.51353 264.28884 362.31007 259 363 C 253.94069 363.91978 248.41624 364.60253 242.4375 365.0625 C 236.45838 365.75232 230.36497 366.09369 224.15625 366.09375 C 202.7699 366.09369 182.66902 363.21768 163.8125 357.46875 C 145.18572 351.71973 128.83992 342.78155 114.8125 330.59375 C 101.0149 318.40591 89.99724 302.85666 81.71875 284 C 73.67016 265.1434 69.62498 242.62166 69.625 216.40625 C 69.62498 191.34082 73.78395 169.38804 82.0625 150.53125 C 90.34099 131.44482 101.35865 115.66798 115.15625 103.25 C 128.95371 90.60246 144.6993 81.17788 162.40625 74.96875 C 180.34293 68.53014 198.99579 65.31275 218.3125 65.3125 z M 225.53125 166.03125 C 217.71247 166.03139 210.93632 167.31435 205.1875 169.84375 C 199.66833 172.37344 195.08545 175.93221 191.40625 180.53125 C 187.72676 184.9006 184.96453 190.19748 183.125 196.40625 C 181.51515 202.3853 180.68737 208.93387 180.6875 216.0625 C 180.68737 230.55 183.82222 242.50925 190.03125 251.9375 C 196.24 261.36588 205.89217 266.06254 219 266.0625 C 223.13909 266.06254 227.3806 265.83496 231.75 265.375 C 236.349 264.68517 240.84934 263.43348 245.21875 261.59375 C 244.75864 259.06426 244.27222 256.18823 243.8125 252.96875 C 243.58234 249.74938 243.46855 246.64579 243.46875 243.65625 L 243.46875 167.78125 C 238.86938 166.6316 232.88975 166.03139 225.53125 166.03125 z "
|
||||
id="rect2987"
|
||||
transform="translate(156.33296,310.4668)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.7 KiB |
40
img/gh.svg
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 568.034 568.034" style="enable-background:new 0 0 568.034 568.034;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M550.99,0H17.051C8.948,0,2.381,6.567,2.381,14.67v538.694c0,8.104,6.567,14.67,14.67,14.67h177.498v-0.129 c8.011-0.092,14.149-4.577,14.431-12.166c0.728-19.725,0.214-39.492,0.214-58.562c-14.296,0.667-27.944,2.473-41.438,1.695 c-29.762-1.714-52.632-14.413-64.493-43.556c-7.026-17.265-17.613-32.032-34.101-41.886c-3.079-1.842-5.771-4.554-8.127-7.308 c-3.079-3.592-2.503-7.282,2.362-8.268c4.908-0.998,10.27-1.695,15.11-0.79c19.009,3.568,32.154,15.49,42.216,31.347 c19.896,31.371,50.521,40.974,84.976,26.487c1.921-0.808,4.363-2.766,4.725-4.553c2.778-13.887,7.968-26.549,18.427-37.65 c-11.628-2.154-22.399-3.739-32.962-6.188c-30.417-7.038-57.742-19.7-77.724-44.848c-16.303-20.514-23.758-44.528-27.185-70.086 c-5.367-40.031-0.563-77.503,26.928-109.493c1.389-1.616,2.142-4.927,1.524-6.94c-6.885-22.497-5.833-44.805,0.991-67.051 c3.581-11.683,4.578-12.265,16.5-10.637c0.729,0.098,1.438,0.281,2.161,0.404c23.898,3.954,44.468,15.526,64.731,27.95 c2.724,1.671,6.873,2.711,9.866,1.983c48.397-11.744,96.702-11.695,145.093,0.043c2.809,0.679,6.561-0.288,9.247-1.695 c11.016-5.759,21.561-12.454,32.718-17.914c12.98-6.346,26.652-11.12,41.371-10.857c2.576,0.049,6.561,2.509,7.423,4.786 c8.856,23.464,10.723,47.375,3.666,71.794c-0.753,2.607,0.367,6.322,1.769,8.892c6.965,12.779,16.689,24.572,21.096,38.127 c13.434,41.316,8.538,82.229-9.749,121.06c-16.757,35.594-47.834,53.63-84.621,62.933c-12.424,3.14-25.153,5.049-38.556,7.681 c17.564,18.348,20.318,40.74,20.006,64.192c-0.324,24.192-0.238,48.391-0.251,72.589c-0.006,11.72,5.11,18.195,14.039,18.574 c-0.006,0.037,188.723,0.037,188.723,0.037V14.67C565.653,6.567,559.087,0,550.99,0z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
41
img/ig.svg
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 455.731 455.731" style="enable-background:new 0 0 455.731 455.731;" xml:space="preserve" width="512px" height="512px">
|
||||
<g>
|
||||
<path d="M314.563,227.866c0,47.881-38.816,86.697-86.697,86.697s-86.697-38.816-86.697-86.697c0-6.872,0.794-13.555,2.31-19.965 h-24.231v114.186c0,6.304,5.119,11.41,11.422,11.41h194.39c6.303,0,11.422-5.107,11.422-11.41V207.9h-24.231 C313.769,214.311,314.563,220.993,314.563,227.866z" fill="#FFFFFF"/>
|
||||
<path d="M325.262,122.589h-30.096c-6.304,0-11.41,5.107-11.41,11.41v30.096c0,6.304,5.107,11.422,11.41,11.422h30.096 c6.303,0,11.41-5.119,11.41-11.422V134C336.673,127.696,331.566,122.589,325.262,122.589z" fill="#FFFFFF"/>
|
||||
<path d="M227.866,281.386c29.551,0,53.521-23.97,53.521-53.521s-23.97-53.521-53.521-53.521c-29.551,0-53.521,23.97-53.521,53.521 S198.315,281.386,227.866,281.386z" fill="#FFFFFF"/>
|
||||
<path d="M0,0v455.731h455.731V0H0z M368.866,338.497c0,14.906-12.086,26.991-26.991,26.991H113.857 c-14.906,0-26.991-12.086-26.991-26.991V117.234c0-14.906,12.086-26.991,26.991-26.991h228.017 c14.906,0,26.991,12.086,26.991,26.991V338.497z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
38
img/sk.svg
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 455 455" style="enable-background:new 0 0 455 455;" xml:space="preserve" width="512px" height="512px">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M285.828,224.324c-6.357-4.187-14.031-7.709-23.039-10.631 c-9.021-2.905-19.071-5.569-30.126-7.963c-8.82-2.069-15.177-3.64-19.005-4.716c-3.776-1.063-7.538-2.533-11.244-4.428 c-3.692-1.881-6.58-4.104-8.649-6.667c-2.034-2.529-3.041-5.499-3.058-9.021c0.017-5.622,2.975-10.408,9.161-14.543 c6.151-4.069,14.284-6.156,24.469-6.156c11.008-0.018,18.904,1.916,23.704,5.626c4.922,3.793,9.144,9.091,12.683,15.872 c2.8,4.874,5.381,8.361,7.844,10.566c2.529,2.271,6.169,3.329,10.815,3.329c5.145,0.017,9.555-1.829,13.007-5.469 c3.452-3.623,5.211-7.774,5.211-12.338c0-4.904-1.365-9.949-4.099-15.089c-2.717-5.145-7.039-10.032-12.902-14.682 c-5.88-4.646-13.265-8.356-22.098-11.161c-8.868-2.8-19.364-4.187-31.461-4.187c-15.159,0-28.389,2.104-39.615,6.326 c-11.261,4.204-19.911,10.268-25.891,18.182c-5.963,7.879-8.956,16.953-8.956,27.086c0,10.631,2.822,19.604,8.492,26.814 c5.657,7.162,13.296,12.819,22.886,16.953c9.586,4.139,21.411,7.726,35.547,10.802c10.526,2.222,18.935,4.323,25.191,6.322 c6.234,1.951,11.261,4.769,15.159,8.479c3.841,3.64,5.723,8.321,5.723,14.219c0,7.398-3.487,13.519-10.749,18.541 c-7.21,4.992-16.647,7.503-28.333,7.503c-8.531,0-15.347-1.229-20.475-3.71c-5.18-2.476-9.178-5.639-12.014-9.432 c-2.857-3.828-5.556-8.632-8.033-14.389c-2.052-4.957-4.581-8.715-7.591-11.296c-3.041-2.599-6.751-3.898-11.091-3.898 c-5.298,0-9.774,1.658-13.261,4.974c-3.434,3.299-5.211,7.332-5.211,11.961c0,7.88,2.853,15.947,8.509,24.185 c5.622,8.238,12.954,14.831,21.976,19.753c12.718,6.891,28.814,10.29,48.265,10.29c16.236,0,30.284-2.494,42.175-7.521 c11.878-4.988,20.952-11.944,27.138-20.847c6.186-8.89,9.297-18.922,9.279-30.096c0-9.262-1.776-17.141-5.364-23.586 C297.229,233.839,292.219,228.511,285.828,224.324z" fill="#FFFFFF"/>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M0,0v455h455V0H0z M296.677,385c-17.019,0-32.896-4.834-46.379-13.143 c-7.433,1.181-15.054,1.781-22.816,1.781c-80.697,0-146.116-65.424-146.116-146.138c0-7.774,0.63-15.348,1.776-22.798 C74.821,191.201,70,175.341,70,158.322C70,109.528,109.546,70,158.323,70c17.019,0,32.896,4.821,46.362,13.142 c7.433-1.164,15.059-1.794,22.816-1.794c80.714,0,146.134,65.419,146.134,146.151c0,7.761-0.613,15.365-1.794,22.798 c8.339,13.484,13.16,29.361,13.16,46.384C385,345.454,345.454,385,296.677,385z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
38
img/tg.svg
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 455 455" style="enable-background:new 0 0 455 455;" xml:space="preserve" width="512px" height="512px">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M0,0v455h455V0H0z M384.814,100.68l-53.458,257.136 c-1.259,6.071-8.378,8.822-13.401,5.172l-72.975-52.981c-4.43-3.217-10.471-3.046-14.712,0.412l-40.46,32.981 c-4.695,3.84-11.771,1.7-13.569-4.083l-28.094-90.351l-72.583-27.089c-7.373-2.762-7.436-13.171-0.084-16.003L373.36,90.959 C379.675,88.517,386.19,94.049,384.814,100.68z" fill="#FFFFFF"/>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M313.567,147.179l-141.854,87.367c-5.437,3.355-7.996,9.921-6.242,16.068 l15.337,53.891c1.091,3.818,6.631,3.428,7.162-0.517l3.986-29.553c0.753-5.564,3.406-10.693,7.522-14.522l117.069-108.822 C318.739,149.061,316.115,145.614,313.567,147.179z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
35
img/tw.svg
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 455 455" style="enable-background:new 0 0 455 455;" xml:space="preserve" width="512px" height="512px">
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M0,0v455h455V0H0z M352.751,163.259c0.123,2.773,0.186,5.561,0.186,8.36 c0,85.403-65.002,183.876-183.873,183.876c-36.496,0-70.466-10.697-99.065-29.037c5.056,0.601,10.199,0.907,15.417,0.907 c30.278,0,58.143-10.331,80.262-27.668c-28.28-0.519-52.148-19.204-60.373-44.88c3.948,0.757,7.997,1.163,12.161,1.163 c5.894,0,11.604-0.794,17.027-2.268c-29.563-5.939-51.841-32.057-51.841-63.368c0-0.273,0-0.544,0.006-0.814 c8.712,4.84,18.676,7.748,29.271,8.084c-17.342-11.589-28.748-31.371-28.748-53.79c0-11.845,3.187-22.945,8.751-32.492 c31.873,39.101,79.493,64.828,133.203,67.526c-1.103-4.732-1.677-9.665-1.677-14.729c0-35.688,28.938-64.623,64.626-64.623 c18.589,0,35.385,7.847,47.173,20.406c14.719-2.895,28.551-8.276,41.038-15.681c-4.824,15.092-15.071,27.754-28.415,35.754 c13.074-1.563,25.528-5.038,37.118-10.178C376.336,142.766,365.38,154.149,352.751,163.259z" fill="#FFFFFF"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
36
img/vk.svg
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 242.667 242.667" style="enable-background:new 0 0 242.667 242.667;" xml:space="preserve" width="512px" height="512px">
|
||||
<path d="M0,0v242.667h242.667V0H0z M177.006,135.224l21.075,24.216c2.694,3.096,0.495,7.925-3.609,7.925h-23.783 c-3.758,0-7.378-1.423-10.13-3.982l-7.043-6.549c-7.948-6.954-11.326-9.339-14.505-9.339c-3.179,0-3.974,2.384-3.974,8.544 c0,6.159-1.192,11.326-19.472,11.326s-32.586-13.71-48.68-34.97c-16.094-21.26-23.247-44.11-23.247-44.11 c-0.888-2.86,1.25-5.762,4.245-5.762h19.032c3.62,0,6.917,2.092,8.435,5.378c1.558,3.373,4.238,8.578,8.822,16.279 c6.505,10.928,12.754,15.851,16.294,17.947c1.318,0.781,2.98-0.184,2.98-1.716V94.199c0-3.43-1.239-6.744-3.49-9.332l-2.683-3.085 c-0.694-0.798-0.127-2.041,0.93-2.041h30.079c4.609,0,8.345,3.736,8.345,8.345v30.483c0,1.964,2.549,2.732,3.634,1.096 l21.649-32.627c1.707-2.572,4.589-4.119,7.675-4.119h25.413c3.473,0,5.585,3.825,3.736,6.765l-22.487,35.741 C174.312,128.502,174.62,132.482,177.006,135.224z" fill="#FFFFFF"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
44
index.html
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>@vladfaust</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="theme-color" content="#e9573f" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=1" />
|
||||
<link href='https://fonts.googleapis.com/css?family=Ubuntu:400' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="stylesheets/style.css">
|
||||
<!-- Yandex.Metrika counter -->
|
||||
<script type="text/javascript"> (function (d, w, c) { (w[c] = w[c] || []).push(function() { try { w.yaCounter33155678 = new Ya.Metrika({ id:33155678, clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); } catch(e) { } }); var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function () { n.parentNode.insertBefore(s, n); }; s.type = "text/javascript"; s.async = true; s.src = "https://mc.yandex.ru/metrika/watch.js"; if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); } })(document, window, "yandex_metrika_callbacks"); </script> <noscript><div><img src="https://mc.yandex.ru/watch/33155678" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||||
<!-- /Yandex.Metrika counter -->
|
||||
</head>
|
||||
<body>
|
||||
<div class="content flex-container">
|
||||
<div class="title flex-item">@vladfaust</div>
|
||||
</div>
|
||||
<div class="footer flex-container">
|
||||
<div class="flex-item">
|
||||
<a class="email-link" href="mailto:hello@vladfaust.com">hello@vladfaust.com</a>
|
||||
<div class="social-icons">
|
||||
<a class="social-icon email-icon" href="mailto:hello@vladfaust.com">
|
||||
<img src="img/em.svg">
|
||||
</a>
|
||||
<a class="social-icon" href="https://telegram.me/vladfaust">
|
||||
<img src="img/tg.svg">
|
||||
</a>
|
||||
<a class="social-icon" href="https://github.com/vladfaust">
|
||||
<img src="img/gh.svg">
|
||||
</a>
|
||||
<a class="social-icon" href="https://vk.com/vladfaust">
|
||||
<img src="img/vk.svg">
|
||||
</a>
|
||||
<a class="social-icon" href="https://twitter.com/vladfaust">
|
||||
<img src="img/tw.svg">
|
||||
</a>
|
||||
<a class="social-icon" href="https://instagram.com/vladfaust">
|
||||
<img src="img/ig.svg">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
30
index.pug
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
eleventyExcludeFromCollections: true
|
||||
pagination:
|
||||
data: collections.all
|
||||
size: 2
|
||||
title: "Vlad Faust Blog"
|
||||
titleNoAppend: true
|
||||
description: "Vlad Faust's personal blog"
|
||||
cover: /public/img/me.jpg
|
||||
---
|
||||
|
||||
doctype html
|
||||
html(lang='en')
|
||||
head
|
||||
include /head.pug
|
||||
|
||||
//- Styles
|
||||
link(rel='stylesheet', href='/public/styles/index.css')
|
||||
body
|
||||
include /header.pug
|
||||
|
||||
main
|
||||
h2 Recent posts
|
||||
ul.posts
|
||||
each post in collections.all.reverse().filter((post) => !post.data.hidden)
|
||||
li
|
||||
span.date= post.date.toDateString()
|
||||
a.title(href=post.url)= post.data.title
|
||||
|
||||
include /footer.pug
|
||||
28
package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "blog",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"debug": "DEBUG=* npx @11ty/eleventy",
|
||||
"dev": "npx @11ty/eleventy --serve",
|
||||
"build": "npx @11ty/eleventy"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Vlad Faust <mail@vladfaust.com>",
|
||||
"license": "None",
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^0.11.0",
|
||||
"@11ty/eleventy-plugin-syntaxhighlight": "^3.0.1",
|
||||
"markdown-it-anchor": "^5.3.0",
|
||||
"markdown-it-attrs": "^3.0.3",
|
||||
"markdown-it-container": "^3.0.0",
|
||||
"markdown-it-footnote": "^3.0.2",
|
||||
"markdown-it-implicit-figures": "^0.10.0",
|
||||
"markdown-it-imsize": "^2.0.1",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0"
|
||||
}
|
||||
}
|
||||
105
posts/2020-08-07-hello-world.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: Hello, World!
|
||||
location: Moscow, Russia
|
||||
excerpt: How many years of programming experience is needed to be qualified to start a tech blog? Time for an introductory post!
|
||||
cover: /public/img/me.jpg
|
||||
ogType: article
|
||||
---
|
||||
|
||||
How many years of programming experience is needed to be qualified to start a tech blog?
|
||||
Ten, fifteen?
|
||||
I see much blogging even with [zero](https://dev.to/), so I decided to give it a try as well.
|
||||
|
||||
Time for an introductory post!
|
||||
|
||||
## I
|
||||
|
||||
I is Vlad Faust.
|
||||
|
||||
I started programming when I was 15, and now [I'm 24](https://www.youtube.com/watch?v=oO3YmT2d-8k){.secret-link}.
|
||||
|
||||
I've gone through many programming environments, from triggers/vJass/cJass in Warcraft® III [custom](https://xgm.guru/p/wc3/headhunter), [maps](https://xgm.guru/p/ufs), to developing and [implementing](https://github.com/fancysofthq/nxc) a [currently-being-standardized](https://nxsf.org/) programming language.
|
||||
|
||||
I've programmed in Pascal, [~~php~~](https://bitbucket.org/vladfaust/anogram-api/src/master){.secret-link style="opacity: 50%;"}, [Java](https://bitbucket.org/vladfaust/jumpinsweeties/src/master/){.secret-link}, Ruby, Javascript, C, C++, C#, C`!@#$%`, C`( ͡° ͜ʖ ͡°)` and many, many more.
|
||||
|
||||
I've created a [game](https://www.moddb.com/games/jumpin-sweeties/videos/trailer) in [LibGDX](https://libgdx.badlogicgames.com/), launched a number of Telegram bots, some of which [did](/public/img/posts/2020-08-07-hello-world/bot-a-users-graph.jpg), [become](/public/img/posts/2020-08-07-hello-world/bot-b-reviews.jpg), [popular](https://t.me/soundmemes/61).
|
||||
|
||||
I've also designed some [other](https://4pda.ru/forum/index.php?showtopic=571231), [games](https://apkpure.com/ruble-fate-raise-the-rouble/com.faustapps.rublefate) and [projects](https://www.dropbox.com/s/xc8kjswj4fb0m0z/presentation.pdf?dl=0).
|
||||
|
||||
<div id="my-open-source"></div>
|
||||
|
||||
In 2016, I fell in love with Ruby with the help of the famous the Michael the Hartl's the [Ruby on Rails Tutorial](https://www.railstutorial.org/), and then even open-sourced some <s>very useful</s> gems:
|
||||
|
||||
* [Jbuilder::JsonApi](https://github.com/vladfaust/jbuilder-json_api)
|
||||
* [AssetPipeline](https://github.com/vladfaust/asset_pipeline)
|
||||
* [SmsActivate](https://github.com/vladfaust/sms_activate)
|
||||
* [Bitcoinpay](https://github.com/vladfaust/bitcoinpay-client)
|
||||
* [Blockchain::Api](https://github.com/vladfaust/blockchain-api)
|
||||
|
||||
I did truly enjoy Ruby on Rails, but after some time, I began wondering if there were more performant alternatives.
|
||||
So I went from Rails to Hanami, and then to Roda and Sequel, and then occasionally run into <s>Assembler</s> [Crystal](https://crystal-lang.org/).
|
||||
|
||||
I instantly got _addicted to Crystal_.
|
||||
Throughout the next two years, I've developed a number of very useful shards:
|
||||
|
||||
* [TimeFormat](https://github.com/vladfaust/time_format.cr)
|
||||
* [I18n](https://github.com/vladfaust/i18n.cr)
|
||||
* [HTTP::Multiserver](https://github.com/vladfaust/http-multiserver.cr)
|
||||
* [Tarantool](https://github.com/vladfaust/tarantool.cr)
|
||||
* [Cake-Bake](https://github.com/vladfaust/cake-bake)
|
||||
* [Callbacks](https://github.com/vladfaust/callbacks.cr)
|
||||
* [Validations](https://github.com/vladfaust/validations.cr)
|
||||
* [MiniRedis](https://github.com/vladfaust/mini_redis)
|
||||
* [HTTP::Params::Serializable](https://github.com/vladfaust/http-params-serializable)
|
||||
* [Migrate](https://github.com/vladfaust/migrate.cr)
|
||||
* [Stripe](https://github.com/vladfaust/stripe.cr)
|
||||
|
||||
I even managed to build my [own web framework](https://onyxframework.org/) featuring a [REST server](https://onyxframework.org/http), a database-agnostic [SQL ORM](https://onyxframework.org/sql) and even an [EDA platform](https://onyxframework.org/eda)!
|
||||
I've also built a (now defunct) [Crystal Jobs](https://github.com/crystaljobs) website and the [RealWorld implementation](https://github.com/vladfaust/crystalworld) in Crystal.
|
||||
|
||||
Unfortunately <s>for Crystal</s>, I've left the Crystal ecosystem, because this is not the language I've always dreamt of.
|
||||
And because of [some](https://github.com/asterite){.secret-link} [other](https://github.com/RX14){.secret-link} reasons, but more on that later.
|
||||
|
||||
In June 2019, I began working on my own programming language, [Onyx](/posts/2020-08-20-the-onyx-programming-language).
|
||||
As of August 2020, it's been more than a year of <s>fighting dragons</s> new knowledge and experiences.
|
||||
|
||||
I invite you all to follow me on this journey.
|
||||
|
||||

|
||||
|
||||
## Am Only Human
|
||||
|
||||
Apart from programming, I used to enjoy heavy-lifting in a local gym.
|
||||
It is not possible now do to [Carpal tunnel syndrome](https://en.wikipedia.org/wiki/Carpal_tunnel_syndrome) I've got the last year.
|
||||
Please do not let that happen to you!
|
||||
|
||||
Me love playing computer and board games with my imaginary friends.
|
||||
My favourite PC games include C&C series, TES series, S.T.A.L.K.E.R. series, Bulletstorm, Carmageddon and [many more](https://store.steampowered.com/app/331470/Everlasting_Summer/){.secret-link}.
|
||||
I'm always happy to play some [Project Winter](https://store.steampowered.com/app/774861/Project_Winter/) with you guys, PM me for a Discord invite!
|
||||
Anyone?
|
||||
|
||||
Human creation is what I enjoy a lot.
|
||||
I love listening to good music and examine great drawings.
|
||||
I can play ukulele and willing to learn the piano and singing.
|
||||
I'm also experimenting with 3D modelling and digital art.
|
||||
|
||||
> [I'll try anything once.](https://gamepedia.cursecdn.com/overwatch_gamepedia/8/81/Echo_-_I%27ll_try_anything_once.ogg){.secret-link}
|
||||
|
||||
Sometime in the future, I plan to work on a strong AI implementation, which you can share music and watch movies together with.
|
||||
This is where [Onyx](/posts/2020-08-20-the-onyx-programming-language) comes into play!
|
||||
|
||||
As a pragmatic person, I wrote some seemingly depressive articles "revealing the truth":
|
||||
|
||||
* [Твой Дзен: Я](https://telegra.ph/Tvoj-Dzen-YA-07-04)
|
||||
* [Твой Дзен: Они](https://telegra.ph/Tvoj-Dzen-Oni-07-04)
|
||||
* [И целого мира не надо](https://telegra.ph/%D0%98-%D1%86%D0%B5%D0%BB%D0%BE%D0%B3%D0%BE-%D0%BC%D0%B8%D1%80%D0%B0-%D0%BD%D0%B5-%D0%BD%D0%B0%D0%B4%D0%BE-12-16)
|
||||
|
||||
On my 24^th^ birthday, I've recorded a [video](https://www.youtube.com/watch?v=qCdGP15vGEc) (in English) accumulating my thoughts on the world and my place in it.
|
||||
|
||||
----
|
||||
|
||||
I think that's enough for an introductory post.
|
||||
Now you know a little bit more about yourself.
|
||||
|
||||
See you around,<br>
|
||||
Vlad.
|
||||
784
posts/2020-08-16-system-programming-in-2k20.md
Normal file
@@ -0,0 +1,784 @@
|
||||
---
|
||||
title: System Programming in 2k20
|
||||
location: Moscow, Russia
|
||||
excerpt: System programming seems to be much harder than application programming. Why is that and how to overcome this?
|
||||
cover: /public/img/posts/2020-08-16-system-programming-in-2k20/state-therof.jpg
|
||||
ogType: article
|
||||
---
|
||||
|
||||
System programming is still essential, but it seems to be much harder than application programming.
|
||||
Why is that and how to overcome this -- these are the questions I'll try to find answers for in this article.
|
||||
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
<h2>Table of Contents</h2>
|
||||
|
||||
${toc}
|
||||
|
||||
## Introduction
|
||||
|
||||
A hundred years ago, a person could not imagine to be able to play any musical instrument they want, to create new interactive worlds, or to launch cars into space.
|
||||
Life was simply not enough.
|
||||
|
||||
Then the machines came.
|
||||
Silicon computations allowed us, mere mortals, prolong our lives virtually and literally.
|
||||
|
||||
Music creation software, game development engines, 2D and 3D editors, neural networks, AI and machine learning, motion capturing, navigation, medicine, wearable devices, smartphones...
|
||||
Thanks to these, a person now can do a lot of things while having more free time during their lifespan.
|
||||
|
||||
It all happened because a human learned to communicate with machines with means of programming languages.
|
||||
Early inventors of the future were brilliant people able to coin fundamentally new concepts which last until today.
|
||||
|
||||
But this is the how the humanity evolves: we accumulate knowledge and pack, shortcut it.
|
||||
We don't need to keep in head proofs of every mathematical theorem, and we don't need to fully understand the nature of an axiom.
|
||||
Instead, we store theorem and axiom statements.
|
||||
With that in mind, we have more space to solve new problems.
|
||||
|
||||
The same applies to programming.
|
||||
Those brilliant people inevitably become old, as real system programming knowledge fades away.
|
||||
On the surface, the amount of those who really understand how machines work seems to shrink.
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet" data-lang="en" data-dnt="true">
|
||||
<p lang="en" dir="ltr">Also this. My aim is to bring ’96 back for ‘20s devs <a href="https://t.co/avFQxxIfpP">pic.twitter.com/avFQxxIfpP</a></p>— Vlad Faust (@vladfaust) <a href="https://twitter.com/vladfaust/status/1264117331820711936?ref_src=twsrc%5Etfw">May 23, 2020</a>
|
||||
</blockquote>
|
||||
|
||||
<figcaption>Hey, that's me!</figcaption>
|
||||
</figure>
|
||||
|
||||
"But I can run a newural network with Python!", one would argue.
|
||||
Well, who do you think develops TensorFlow itself?
|
||||
TensorFlow [isn't written in Python](https://github.com/tensorflow/tensorflow), kid.
|
||||
|
||||
Writing a game in Lua or Ruby is totally possible, as well as creating a messenger or code editor in Electron.
|
||||
However, Electron, as any mature game engines, are still written in [C++](https://github.com/electron/electron).
|
||||
|
||||
Almost any meaningful software which needs to utilize a machine with more than [20%](https://en.wikipedia.org/wiki/Pareto_principle){.secret-link} efficiency, is written in a system programming language.
|
||||
|
||||
::: hero
|
||||
|
||||
System programming is the foundation of the development of the human civilization.{style="font-size: 2.25rem"}
|
||||
|
||||
:::
|
||||
|
||||
Regardless of its importance, system programming seems to be less popular than application programming, because it's known to be harder to both learn and master.
|
||||
It is definitely easier to spin up a web server, connect it to a database, set up some Stripe integration, drink a smoothie and proudly call yourself an entrepreneur.
|
||||
|
||||
But that does not invest in the human civilization's progress on the Kardashov's scale.
|
||||
<mark>The humanity will still depend on system programming in the foreseeable future.</mark>
|
||||
And we need new, fresh blood there.
|
||||
|
||||
In this article, I'll try to take a peek on the current state of the system programming, find out why it's not that popular and choose the best system programming language for the Next Big But Fairly-Low-Level Project (tm).
|
||||
|
||||
## Choosing the Right Language
|
||||
|
||||
When choosing a serious language for serious system programming, the choice is broad: it's either C, C++, Rust, or one of the many new LLVM-based projects.
|
||||
|
||||
### C
|
||||
|
||||
C is excellent at its simplicity, but bigger projects require higher-level language features, such as [memory control](https://twitter.com/jfbastien/status/1289305925199650816), object hierarchy, lambdas etc.; therefore, C is out of competition here.
|
||||
|
||||
Ditto applies to C "replacements", such as [Ẕ̴̰̥̔͝i̷̥̣̍̓̉ġ̷̢̪͌̾́](https://ziglang.org/) and [Patreon-lang](https://vlang.io/).
|
||||
|
||||
### C++
|
||||
|
||||
C++ is the grandfather of higher-level system programming.
|
||||
|
||||
It offers powerful features with a grain of Unix epoch practices and a great amount of undefined behaviour.
|
||||
Funnily enough, an experienced C++ programmer shall aware of not what C++ is, but of what it is not, i.e. undefined behaviour of the language.
|
||||
|
||||
That said, developing on C++ is pain, and it is easy to shoot your lower parts off by, say, returning a lambda with a closured local variable.
|
||||
Of course, it is possible to have a fancy third-party UB checking tool, but such a tool would never be perfect considering the amount of UB in the language itself.
|
||||
|
||||

|
||||
|
||||
Another Unix anachronism C++ inherits is the backwards compatibility with a bitter taste of Postel's law: "most compilers implement that feature in different ways, let's put it into the language after a short thought with design averaging from existing implementations!".
|
||||
One may argue that backwards compatibility is a good thing, but let me postpone this discussion for a [later section](#backwards-compatibility) of this article.
|
||||
|
||||
### Rust, pt. 1
|
||||
|
||||
Rust is a fairly young programming language with a reputable mission: empower everyone to build reliable and efficient software.
|
||||
Let's deconstruct the statement.
|
||||
|
||||
One of the game-changing features of Rust is the separation between safe and unsafe code.
|
||||
The ability to isolate volatile code worths a lot: if anything goes wrong, then you simply `grep` your codebase with `unsafe` filter and voilà -- all the dangerous invocations are at your hand sight.
|
||||
It also allows _the_ implementation to perform crazy optimizations, say, by entirely removing parts of code; and it's fine because there is no unsafe access to that code.
|
||||
As a result, focusing on volatile code becomes easier, and nasty bugs are squashed faster.
|
||||
|
||||
Otherwise, _the_ Rust compiler would yell at you, pointing at your mistakes in the safe code area.
|
||||
And those yells are detailed enough, so most of the time you have a clear picture on why you're wrong and what to do with that.
|
||||
|
||||
Compared to C++, Rust compilation process is much friendlier and catches more bugs before you face them in runtime.
|
||||
|
||||

|
||||
|
||||
Another good thing about Rust is macros.
|
||||
Well, what's good is the idea of macros; the implementation of macros in Rust is um... questionable.
|
||||
Nevertheless, macros allow writing code in code with much greater flexibility than with C++ preprocessor and constant expressions.
|
||||
Nuff said, macros are must-have in modern languages.
|
||||
|
||||
The built-in crates system Rust has brings powerful abstractions into the ecosystem.
|
||||
Those folks enjoying lower-level programming and having enough skills to do so can wrap unsafe, but performant code, into simple, but safe abstractions.
|
||||
And those who have a need to just make things work, may (comparably) [easy adopt those crates](https://www.theregister.com/2020/01/21/rust_actix_web_framework_maintainer_quits/).
|
||||
|
||||
----
|
||||
|
||||
<!--  -->
|
||||
|
||||
Rust really does allow to build _reliable_ (no undefined behaviour in-the-wild) and _efficient_ (thanks to the zero-cost philosophy) software to _everyone_ (with powerful abstractions).
|
||||
|
||||
But, there are always some "but<sub>t</sub>s".
|
||||
|
||||
First of all, only a few may say Rust has friendly syntax.
|
||||
In the maniacal pursuit for the absolute memory safety, the language introduces plethora of abstractions such as borrow checker, six string types (hey, we're making a language here, not a guitar), `Mut`, `Box`, `Arc`, `Trait`, requiring to do those ubiquitous `unwrap()`, `as_ref()` and `borrow()` (often chained) literally before every access.
|
||||
|
||||
Some may call it "hipster thinking", but those small spikes like mandatory semicolons\*, curly brackets wrapping, and otherwise unintuitive design decisions like constantly "screaming code" with ubiquitous bangs (`!`) and overloaded documentation semantics — they make writing and reading Rust code harder.
|
||||
Definitely harder than Ruby or, say,
|
||||
J̸̧̨̹͈̦̏̅͒̈́͂͐̄̾͟͟ͅȃ̡͎̯̟̦͉͂͊̿̈́v̢̡͖͍̻̳̞͌͌̈̋̐͌̆͜a̴͖̱̟̩̹̘̺͊̃̋̇̾̀̀͐̊͐ͅS̶͚̣̥͚͈̥̤͔̾̎̎̿̔͊̋̉̓c̶̡̧̗̻̊̈̋̍̔̂̅̓̚͘͢ŗ̰͖̲̙͖͕̂̏̍͑̊̋ḯ̸̛̤̦̠͈̩̙̯̘̥̖̅́̊̀͑̕͠͠p̸̨̧̨̧̡̛̮̯͖̹͈̉̑̿͛̎̀͌̾͞ț̸̩͕͈̊͐̏̏̕͡ͅ
|
||||
.
|
||||
|
||||
|
||||
::: off
|
||||
|
||||
\* In fact, semicolons are not mandatory
|
||||
_everywhere_
|
||||
, which brings even more confusion.
|
||||
|
||||
From [StackOverflow](https://stackoverflow.com/questions/26665471/are-semicolons-optional-in-rust):
|
||||
|
||||
> Semicolons are generally not optional, but there are a few situations where they are. Namely after control expressions like `for`, `if/else`, `match`, etc.
|
||||
|
||||
[Bruh.](https://www.myinstants.com/media/sounds/movie_1.mp3){.secret-link}
|
||||
|
||||
:::
|
||||
|
||||
A [wise man](https://en.wikipedia.org/wiki/Jason_Statham){.secret-link} once said:
|
||||
|
||||
> The complexity of a language feature is proportional to the number of articles explaining the feature.
|
||||
|
||||
Here go a tiny fraction of reads on why Rust is not even nearly to an intuitive language:
|
||||
|
||||
1. [Common Rust Lifetime Misconceptions](https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md)
|
||||
|
||||
1. [What Not to Do in Rust](https://blog.sentry.io/2018/04/05/you-cant-rust-that?utm_content=137995710)
|
||||
|
||||
1. [Frustrated? It's not you, it's Rust](https://fasterthanli.me/articles/frustrated-its-not-you-its-rust)
|
||||
|
||||
1. [Understanding lifetimes](https://www.reddit.com/r/rust/comments/ic67tm/understanding_lifetimes/) (the subreddit itself is straight proof of how insanely complex the language is)
|
||||
|
||||
1. [Understand smart pointers in Rust
|
||||
](https://stackoverflow.com/questions/55075458/understand-smart-pointers-in-rust) (the StackOverflow tag is full of that gold)
|
||||
|
||||
1. [Clear explanation of Rust’s module system](http://www.sheshbabu.com/posts/rust-module-system/)
|
||||
|
||||
The following is my personal collection of "why I love Rust".
|
||||
|
||||
::: spoiler ⚠️ Lots of nasty tweets inside
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet">
|
||||
<p lang="en" dir="ltr">The learning curve of <a href="https://twitter.com/rustlang?ref_src=twsrc%5Etfw">@rustlang</a> for whoever is used to GC languages is steep but very interesting. Like, this code does *not* compile in Rust, but it actually makes a lot of sense 🤯:<a href="https://twitter.com/hashtag/programming?src=hash&ref_src=twsrc%5Etfw">#programming</a> <a href="https://t.co/yLru0bQ0gV">pic.twitter.com/yLru0bQ0gV</a>
|
||||
</p>— Rémi Sormain (@RSormain) <a href="https://twitter.com/RSormain/status/1287395421736898560?ref_src=twsrc%5Etfw">July 26, 2020</a>
|
||||
</blockquote>
|
||||
|
||||
<figcaption>No, it does not</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">A nasty compiler error to start the morning. (pages of this) <a href="https://t.co/vvMqcOsYcC">pic.twitter.com/vvMqcOsYcC</a></p>— Luca Palmieri 🦊 (@algo_luca) <a href="https://twitter.com/algo_luca/status/1286935357083340801?ref_src=twsrc%5Etfw">July 25, 2020</a></blockquote>
|
||||
|
||||
<figcaption>You'd better start with coffee</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet">
|
||||
<p lang="en" dir="ltr">This is fine, just a perfectly normal function signature. <a href="https://t.co/qotj5f3ndb">pic.twitter.com/qotj5f3ndb</a>
|
||||
</p>— Bodil Stokke, Esq. (@bodil) <a href="https://twitter.com/bodil/status/1259127749169631232?ref_src=twsrc%5Etfw">May 9, 2020</a>
|
||||
</blockquote>
|
||||
|
||||
<figcaption>That's alright, they find a way to reduce it in the replies</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">What is this even.<a href="https://t.co/0oUvVMJYEC">https://t.co/0oUvVMJYEC</a></p>— James Munns (@bitshiftmask) <a href="https://twitter.com/bitshiftmask/status/1227021520133853184?ref_src=twsrc%5Etfw">February 11, 2020</a></blockquote>
|
||||
|
||||
<figcaption>Those signatures tho</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet">
|
||||
<p lang="en" dir="ltr">when my backend looks like this so her frontend can look like that <a href="https://t.co/xV4d6bi7ge">pic.twitter.com/xV4d6bi7ge</a></p>— Yaah 🦀 (@yaahc_) <a href="https://twitter.com/yaahc_/status/1293411590964830208?ref_src=twsrc%5Etfw">August 12, 2020</a>
|
||||
</blockquote>
|
||||
|
||||
<figcaption>ditto</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet">
|
||||
<p lang="en" dir="ltr">Methods with a variable number of parameters in <a href="https://twitter.com/rustlang?ref_src=twsrc%5Etfw">@rustlang</a>.<br><br>AMA.<br>😭 <a href="https://t.co/IJ77fMLGPp">pic.twitter.com/IJ77fMLGPp</a></p>— Luca Palmieri 🦊 (@algo_luca) <a href="https://twitter.com/algo_luca/status/1296732882237612034?ref_src=twsrc%5Etfw">August 21, 2020</a>
|
||||
</blockquote>
|
||||
|
||||
<figcaption>Did someone said "macros"?</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">What is the correct <a href="https://twitter.com/rustlang?ref_src=twsrc%5Etfw">@rustlang</a> borrowing trait to impl for a wrapper type that enforces an invariant (i.e. NonZero*) but where otherwise you want it to be usable anywhere the inner type is usable? (note: poll, not quiz)</p>— Tony “Abolish (Pol)ICE” Arcieri 🦀 (@bascule) <a href="https://twitter.com/bascule/status/1299084955025203200?ref_src=twsrc%5Etfw">August 27, 2020</a></blockquote>
|
||||
|
||||
<figcaption>What. The. Fuck.</figcaption>
|
||||
</figure>
|
||||
|
||||
:::
|
||||
|
||||
And sorry for these (you can open them in a new tab to enlarge (but please don't)).
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
----
|
||||
|
||||
<mark>Rust is more confusing than C++</mark>, change my mind.
|
||||
On the one side, _the_ compiler is always watching your moves, and it is responsible for ensuring protection from undefined behaviour...
|
||||
But that power comes at the price of unfriendly, clumsy, cumbersome syntax with lots of unintuitive abstractions and repetitive actions.
|
||||
Now, instead of keeping in mind of where C++ might blow, one shall be aware all the abstractions Rust brings in to choose the right one, <small>and where to place a semicolon</small>.
|
||||
|
||||
That said, the "for everyone" clause in the mission statement seems unfair to me now.
|
||||
It takes great effort to become fluent in Rust.
|
||||
|
||||
Regarding other two clauses in the Rust's mission, I still have no claims on them.
|
||||
Rust programs are known to be reasonably performant (<small>if you ever manage to wait until `rustc` compiles with optimizations turned on</small>), and there is even the academia-grade [RustBelt](https://plv.mpi-sws.org/rustbelt/) organization ensuring the UB-safety.
|
||||
|
||||
You can always find more on what's the good, the bad and the ugly about Rust, but the main point is that <mark>the language is not ideal</mark>, and there is definitely room for improvements.
|
||||
Plus one point to the justifying.
|
||||
|
||||
### Challengers Worth Mentioning
|
||||
|
||||
There are some other noteworthy languages, which nevertheless do not fit my requirements for [various reasons](https://en.wikipedia.org/wiki/Not_invented_here).
|
||||
|
||||
#### Julia
|
||||
|
||||
[Julia](https://julialang.org/) is quite a mature language focused on **scientific research**.
|
||||
|
||||
First of all, I'm interested in a general-purpose language.
|
||||
I want to be able to create mainstream GUI applications, microservices and 3D engines, while Julia is focused on multi-dimensional arrays and plots.
|
||||
|
||||
::: spoiler Second of all,
|
||||
|
||||

|
||||
|
||||
:::
|
||||
|
||||
You can find more on why not Julia [here](https://www.zverovich.net/2016/05/13/giving-up-on-julia.html), with critique addressed [here](https://www.reddit.com/r/Julia/comments/629qkz/about_a_year_ago_an_article_titled_giving_up_on/).
|
||||
|
||||
Check out [another hilarious post](https://discourse.julialang.org/t/get-it-together-guys/27826) on this matter.
|
||||
I personally love this quote:
|
||||
|
||||
> Get a job! Then paint your masterpiece.
|
||||
|
||||
Telling that to a scientific language developed in MIT by scientists...
|
||||
Well, more on that later.
|
||||
|
||||
#### Nim
|
||||
|
||||
[Nim](https://nim-lang.org/) is a magnificent piece of art.
|
||||
|
||||
But it has a Python-like indentation-based syntax with less flexible `import` semantics.
|
||||
It lacks proper object-oriented features like interfaces and mixins.
|
||||
And it does not have lower-level features like pointer arithmetics, address spaces etc.
|
||||
|
||||
#### Crystal
|
||||
|
||||
I love the core idea behind Crystal.
|
||||
I don't like its implementation.
|
||||
|
||||
They are saying that [Crystal](https://crystal-lang.org/) is a general-purpose programming language, but that's not true.
|
||||
The language and its core team are focused on their needs, which is solely an `amd64-linux` platform.
|
||||
|
||||
The standard library is bloated with heavy dependencies like `libxml` and `libyaml`, the language itself has GC, event loop and unwinding-based exceptions (i.e. a runtime) built-in, and it's therefore hardly possible to ship an executable for purposes other than serving requests over HTTP.
|
||||
|
||||
After almost 10 years in development, the core team still has disagreements in the fundamental design, and you may commonly see controversial claims by its officials regarding Crystal's future on the forum.
|
||||
They even can not decide if Crystal is a compiled Ruby or something else.
|
||||
|
||||
<!-- TODO: Reference example issues and posts here. -->
|
||||
|
||||
Regarding the number of bugs the only implementation has...
|
||||
Once you dig a little bit deeper, it all begins to explode.
|
||||
Macros, generics, unions, interoperability: it may blow up anywhere.
|
||||
A core team [representative](https://github.com/asterite){.secret-link} without "core team" badge will then appear telling you that <small>it's not a bug, or wait, it is a bug, but it can not be fixed, oh wait, it can be fixed, but it's not a bug, issue closed, thanks</small>.
|
||||
|
||||
<!-- TODO: There tons of examples of such behaviour, should put them here. -->
|
||||
|
||||
The recently introduced multi-threading brings even more problems due to the lack of proper addressing of the data races in the language.
|
||||
As most of the other design decisions in Crystal, this one has been taken somewhere in Manas without any open discussion.
|
||||
|
||||
I've spent two years in the Crystal ecosystem, and it did not move forward a bit, only backwards (bye, [Serdar](https://twitter.com/sdogruyol), bye [Julien](https://twitter.com/ysbaddaden)).
|
||||
A brilliant idea is buried by lack of focusing on the community needs.
|
||||
A hard lesson to learn.
|
||||
It's time for (_spoiler alert_) Crystal done right.
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
One would now jump into proudly announcing another language they've come up with, a utopia-grade solution to replace both C++ and Rust once and forever.
|
||||
|
||||
But the "forever" claim is kinda sloppy.
|
||||
|
||||
Remember how I mentioned earlier that backwards compatibility is not _that_ good?
|
||||
The truth is that there will always be unforeseeable new features at some point, which have to be implemented, so a language stays competitive.
|
||||
For example, coroutines, a term coined in 1958, were not much of interest until 2010's...
|
||||
|
||||
A product aiming to preserve backwards compatibility has to somehow insert new features into existing rules without introducing breaking changes.
|
||||
|
||||
C++ is an excellent primer on how not to.
|
||||
Constrained by existing implementations, they add overly complicated `co_await` functionality into the standard library with extra garbage, which instead should have been built into the language itself (the functionality, not the garbage).
|
||||
|
||||
Another ad-hoc example is C++20 concepts.
|
||||
Instead of allowing to restrict generic arguments in-place, a new `requires` syntax is added, which is quite cumbersome: see [this](https://akrzemi1.wordpress.com/2020/01/29/requires-expression/) and [this](https://akrzemi1.wordpress.com/2020/03/26/requires-clause/).
|
||||
|
||||
As the hardware evolves, new fundamental types come into play.
|
||||
What's the state of support of SIMD vectors, tensors or half-precision floats in C++? Brain floats?
|
||||
Oh please.
|
||||
Instead of being incorporated into the standard, implementations come with their own solutions, which further invests into the chaos.
|
||||
|
||||
But breaking changes are always painful, you would argue because on one side you want to use all the shiny new features, but on the other, you don't want to spend a dime rewriting your code.
|
||||
It becomes even worse when an open-source library author you're depending on decides that they will not support the older major version of a language; or, instead, they won't move on to the newer version.
|
||||
|
||||
Given the number of open-source libraries your project depends on, you are in trouble, as library versions become stale or incompatible.
|
||||
|
||||
All that's left is to visit a library's bug tracker and leave a "what's the status of this?" or "+1" comment, or maybe even put a little bit more effort:
|
||||
|
||||
[](https://github.com/vladfaust/unity-wakatime/issues/25)
|
||||
|
||||
When deciding on which language to build your next big project™ in, what you (or your PM) really want is that it accounts for all the present and future software and hardware features, has ultimate performance, maintainability, and never introduces any breaking changes, so you constantly reap the rich choice of forever-actual libraries.
|
||||
|
||||
Of course, such a language should be free as beer, as all of the forever-actual libraries.
|
||||
What's the point otherwise?
|
||||
|
||||
## Rust, pt. 2
|
||||
|
||||
Looks like Rust is the perfect candidate.
|
||||
|
||||
In the famous [Rust: A Language for the Next 40 Years](https://www.youtube.com/watch?v=A3AdN7U24iU) talk, they say that Rust will never have a major breaking change, staying <s>young</s> version `~> 1` forever, but still evolving.
|
||||
|
||||
Wait a minute.
|
||||
|
||||
At 32:15, Carol says:
|
||||
|
||||
> When I first heard of that idea, I thought it sounds terrible from the compiler maintenance point of view: you have to maintain two ways to use every feature forever because we wanted to commit to all editions being supported forever. But it's actually not that bad.
|
||||
|
||||
Then they take a good thinking sip of water and prove that it is indeed that bad.
|
||||
|
||||
[](https://youtu.be/A3AdN7U24iU?t=1822)
|
||||
|
||||
Effectively, the "forever `~> 1`" policy limits the number of fundamental features Rust MIR can have changed.
|
||||
According to the talk, only a few keywords are to differ between editions.
|
||||
|
||||
So what we have in the dry run is a never-really-changing language with some slightly-different dialects to support.
|
||||
Occasionally, an implementation would opt-out of supporting an edition, and consequently all the libraries written in this edition become unusable.
|
||||
No ecosystem split, huh?
|
||||
|
||||
The editions problem could be addressed by supporting multiple editions in a single library.
|
||||
But what if a library author you're depending on decides that they will not support a specific edition...
|
||||
Um.
|
||||
|
||||
> [Ever got that feeling of déjà vu?](https://static.wikia.nocookie.net/overwatch_gamepedia/images/c/c0/Tracer_-_Ever_get_that_feeling_of_d%C3%A9j%C3%A0_vu.ogg){.secret-link}
|
||||
|
||||
Yes, we're back to breaking changes and supporting multiple incompatible major <s>versions</s> editions of a language.
|
||||
Oh those lazy open-source, free, OSI-licensed library maintainer bastards, they are the evil root of all the problems!
|
||||
|
||||
## On Open-Source Sustainability
|
||||
|
||||
For some, programming is just a job.
|
||||
|
||||
For others, programming is a form of artistic expression.
|
||||
For artists, writing open-source software facilitates the top two levels of the Maslow's hierarchy: self-actualization and esteem.
|
||||
They enjoy writing clean, well-documented code, so anyone using it could feel the same.
|
||||
|
||||
Guess who creates (a significant portion of) quality open-source software?
|
||||
|
||||

|
||||
|
||||
The above certainly applies to me.
|
||||
|
||||
I used to maintain a [number](https://github.com/vladfaust?tab=repositories&q=&type=&language=crystal) of Crystal projects, most of which were well-documented and optimally performant.
|
||||
I enjoyed writing [documentation](http://github.vladfaust.com/mini_redis/index.html) and [compiling changelogs](https://github.com/vladfaust/mini_redis/releases/tag/v0.2.0).
|
||||
I even enjoyed [replying to issues](https://github.com/vladfaust/unity-wakatime/issues/25), to reveal [unexpected use-cases](https://github.com/vladfaust/migrate.cr/issues/12), [add new features](https://github.com/vladfaust/unity-wakatime/pull/11) and [squash bugs](https://github.com/vladfaust/unity-wakatime/pull/23) together.
|
||||
|
||||
The greatest project of mine in Crystal was the [Onyx Framework](https://onyxframework.org), a web framework comprised of a REST server, a database-agnostic SQL ORM and even EDA facilities.
|
||||
I was planning to also implement a GraphQL framework module, and a convenient CLI to ease the development process.
|
||||
Objectively, it is more user-friendly, a better balanced between features and usability, than alternatives.
|
||||
|
||||
You can find out more about my journey in programming in the [introductory post](/posts/2020-08-07-hello-world/).
|
||||
|
||||
### Primitive Needs to Be Ashamed Of
|
||||
|
||||
An artist, like any other human, has more needs to satisfy, though.
|
||||
These are safety and psychological needs.
|
||||
In other words, a man gotta pay his bills.
|
||||
|
||||
Was I able to pay my rent with open-sourcing?
|
||||
|
||||
> [LOL, haha!](https://static.wikia.nocookie.net/overwatch_gamepedia/images/a/a4/D.Va_-_Lol.ogg){.secret-link}
|
||||
|
||||
Nowadays, a senior iOS developer in Russia has a salary of about $4'000 (300'000₽), which is $25 per hour.
|
||||
|
||||
At the best times, my salary as an Open-Source engineer was pathetic $70.
|
||||
|
||||

|
||||
|
||||
I did receive some "tokens of appreciation" from companies a couple of times, but those were not regular, and I could certainly not have a decent living even with them.
|
||||
|
||||
You may argue that it was my fault to choose a promising young language with sweet syntax and native performance to invest my time in, but reread this sentence.
|
||||
|
||||
----
|
||||
|
||||
Is it easy to pay your bills when you're a poet?
|
||||
|
||||
Poetry is a basic form of art, but only a few, from many talented, poets can make their living doing what they love.
|
||||
Given the same talent level, it takes big luck to become recognized and earn enough to pay rent.
|
||||
|
||||
Some poets may come to streets and start reciting their poetry, hoping for a dime donated.
|
||||
Some are more than happy to be hired by a children book publishing company which needs lots of similar poems...
|
||||
As the individualism fades away.
|
||||
|
||||
<!-- TODO: I can't remember a Javascript repository with brilliant sentences like "if you liked the code, maybe check out my patreon 😂😂😂, but if you want 😂😂😂, sorry 😂😂😂". -->
|
||||
|
||||
There are several paths for an open-source maintainer:
|
||||
|
||||
1. To spend their time entirely for free.
|
||||
1. To spend their time entirely for free, but put a link to their pitiful $0.0002/week Liberapay account, which would inevitably infuriate some Rabadash8820.
|
||||
It is also required to always wrap the links with "😂" emojis and constantly [feel bad](https://clips.twitch.tv/RacyImpossibleTubersWTRuck) about asking to compensate for your time.
|
||||
The fuck?
|
||||
1. To sell their time as a software consultant and provide direct support for their libraries.
|
||||
These are often sold under the donations sauce and imply the same shameful constraints.
|
||||
1. To choose one of the explicit business model paths, such as open-core, where the product is not an open-source anymore, but a real business with marketing, cold calls, email spam, free trials etc.
|
||||
|
||||
Regarding working for free (paths 1 and 2), I love this quote by myself:
|
||||
|
||||
> Companies rely on those spending their precious time for free in the hope of being hired by those companies.
|
||||
> A Saṃsāra's circle to break.
|
||||
|
||||
Compared to poetry, the consultancy path (3) is like giving interviews and explaining your poems to others verse-by-verse. Which is not that bad.
|
||||
Although sometimes you want to spend your time on writing new poems instead of explaining the old ones.
|
||||
Moreover, some precious time has already been put into an old poem and shall be compensated as well.
|
||||
Musicians do not tend to give their already written songs for free, do they?
|
||||
|
||||
Regarding an explicit business path (4), I believe that it has the same consequences for software as for poetry or music.
|
||||
An artist starts to think about money more than art, which inevitably leads to worse quality.
|
||||
For example, in the open-core model, a maintainer spends resources on consciously deciding which features are to be deleted from the "open" part, and how to glue them with the paid part.
|
||||
|
||||
That being said, are there any other ways to sustain open-source, <mark>to make open-sourcing a _real job_</mark>?
|
||||
|
||||
### Source-On-Demand
|
||||
|
||||
For musicians, there are platforms like Spotify, where a listener pays a fixed amount of money regularly, and the platform pays a musician based on how popular they were during the period.
|
||||
|
||||
Can it be applied to model open-source sustainability?
|
||||
|
||||
One of the problems arising is how to determine the "popularity" of an open-source library.
|
||||
Is that the number of unique downloads ("launches")?
|
||||
Or maybe some sort of manually-triggered endorsements?
|
||||
|
||||
Also, a library may still be useful, but too specific, hence not "popular".
|
||||
Its maintenance would still require a comparable amount of resources.
|
||||
|
||||
The solution may be an algorithm taking into consideration both downloads from, say, unique IP addresses, per month, and manual endorsement actions like claps on Medium.
|
||||
Unfortunately, highly-narrowed, hence unpopular, libraries would still have to look for other sources of funding.
|
||||
|
||||
Okay, this looks like a good plan.
|
||||
But.
|
||||
In the music world, an artist becoming obsessed with the number of streams rather than with the quality of their music, either loses its popularity or changes trends towards <s>shitty</s> lesser-quality music.
|
||||
|
||||

|
||||
|
||||
Could the same thing happen in the open-source world?
|
||||
Yes.
|
||||
A greedy (or lucky) programmer may create a ton of `is-even()`-like libraries to be occasionally present as a dependency in a plethora of libraries.
|
||||
Do they deserve to be rewarded?
|
||||
Absolutely.
|
||||
They do create value recognized by dependants, and this shall be properly rewarded.
|
||||
Does it make the overall situation worse?
|
||||
Yes, because there eventually is a larger amount of libraries to be aware of and put into dependency lists.
|
||||
Generally, the more dependencies there are, [the worse](https://blog.carlmjohnson.net/post/2020/avoid-dependencies/).
|
||||
|
||||
::: spoiler A classic meme
|
||||
|
||||
<div style='position:relative; padding-bottom:calc(55.00% + 44px)'>
|
||||
<iframe src='https://gfycat.com/ifr/SmugCautiousFrogmouth' frameborder='0' scrolling='no' width='100%' height='100%' style='position:absolute;top:0;left:0;'></iframe>
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
It is clear that value created by a single `is-even()` library is incomparable to value created by, say, a PostgreSQL driver depending on it.
|
||||
It would be unfair to award a single "use" of an `is-even()` library equally to the driver "use".
|
||||
How to clearly determine the value then?
|
||||
|
||||
I bet on the number of characters in a library's source code, including those commented (because documentation matters) and in binary files.
|
||||
As a result, it would be more profitable to release big libraries: a user would likely require only the files they need (making an overall library size irrelevant to the compilation time), but the algorithm would still count the total amount of lines of code in a library, regardless of which files are required.
|
||||
|
||||
One may argue that such a design would encourage Indian-style coding, with lots of repetitions and other crazy practices.
|
||||
But libraries are typically designed for reuse and continuous maintenance, which means periodically adding new bugs and removing features.
|
||||
This is not a one-time freelance job.
|
||||
|
||||
Even if one decides to go sneaky and publish lots of hardly maintainable code, then, well, they will lose the competition, because they will not be able to maintain the code themselves.
|
||||
|
||||
Given a choice, a business shall choose a library whichever is maintained and documented better, and whichever compiles and runs faster.
|
||||
This is not about music taste getting worse, when a user would continue listening to whatever <s>shitty</s> low-effort product is released. It is about clearly defined business needs when compile-time and runtime cost actual money.
|
||||
|
||||
Moreover, when a maintainer has a decent user base paying the bills, hence reputation, they (a maintainer) would take on security [more seriously](https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/).
|
||||
|
||||
<!-- Oh, and manual endorsements should only be made possible from those "paying" customers so that only actual users of an endorsed library affect its funding. -->
|
||||
|
||||
The model seems win-win to me, at least theoretically.
|
||||
I don't know if it would work in reality, but I guess it's worth trying.
|
||||
|
||||
Let's call the model "source-on-demand".
|
||||
|
||||
#### Impact On A Language
|
||||
|
||||
Let's imagine we've solved the open-source sustainability problem by implementing a source-on-demand service for one language ecosystem.
|
||||
What benefits would the language experience?
|
||||
|
||||
A real market with healthy competition attracts new library authors and incentivizes the old ones to continue maintenance to stay competitive.
|
||||
That means more libraries in general and less stale issues.
|
||||
|
||||
A rich, constantly growing ecosystem attracts new developers, which in turn implement libraries for their own usage, and maybe occasionally publish them.
|
||||
|
||||
<mark>**A healthy competition in the ecosystem frees the language from the backwards compatibility burden.**</mark>
|
||||
Once it (the language) introduces a breaking change, it's up to library authors to support the new version.
|
||||
If they decide to drop support for a major language version which is in use, others will likely take the spot.
|
||||
|
||||
Wow.
|
||||
Let's try applying the model to existing languages.
|
||||
|
||||
#### A C++ Implementation
|
||||
|
||||
_A crazy-looking old man with wild hair steps onto the scene._
|
||||
|
||||
Alright kids, now we're about to build a C++ library hosting service with the source-on-demand model.
|
||||
|
||||
Where do we begin?
|
||||
First of all, we need to look at existing solutions.
|
||||
Okay, Google, `c++ package managers`.
|
||||
[Here](https://stackoverflow.com/questions/27866965/does-c-have-a-package-manager-like-npm-pip-gem-etc) is the most voted answer on the matter:
|
||||
|
||||
> _There seem to be a few though I've never used them._
|
||||
|
||||
Well, this is one of the first results a user looking for a C++ package manager stumbles into.
|
||||
_Not great, not terrible._
|
||||
|
||||
Anyway, the only relevant (and alive) projects I could find are [Conan](https://conan.io/), [Buckaroo](https://buckaroo.pm/), [Hunter](https://github.com/cpp-pm/hunter), [VCPKG](https://github.com/Microsoft/vcpkg) and [Pacm](https://sourcey.com/pacm/).
|
||||
Neither of which is centralized.
|
||||
They all propose to either set up their own package server or download packages directly from sources.
|
||||
|
||||
But what about observability?
|
||||
How does one find C++ packages to use in their projects?
|
||||
What I if want, for example, an HTTP server package?
|
||||
My variants are either [Googling](https://lmgtfy.com/?q=c%2B%2B+http+server+library), [GitHubbing](https://github.com/search?q=c%2B%2B+http+library), asking on [Reddit](https://www.reddit.com/r/cpp/comments/cjj9t5/what_c_web_server_library_one_should_use_nowadays/), lurk through manually maintainted [lists of libs](https://en.cppreference.com/w/cpp/links/libs)...
|
||||
There is definitely a pain to solve!
|
||||
|
||||
::: off
|
||||
|
||||
While working on this article, I've tried VCPKG, and it's pretty damn good in the current stage.
|
||||
It has its problems like inability to select a compiler on Windows or select a compiler in principle, which leads to standard compatibility issues.
|
||||
The latter is more of the loose- C++ -standard issue.
|
||||
|
||||
:::
|
||||
|
||||
Imagine a shiny new world <s>order</s> with a centralized repository of C++ libraries with good searching features, tags, compatibility information etc.!
|
||||
|
||||
Would it actually change anything in <s>current government</s> C++?
|
||||
I doubt so.
|
||||
|
||||
C++ is archaic by itself!
|
||||
|
||||
Breaking changes to C++ aren't possible even if a centralized on-demand library manager was solving the library funding problem.
|
||||
There is no fresh blood in C++, most of the youngsters do not want to bear with poor design the language imposes by itself.
|
||||
The amount of time needed to convince Stroustrup-aged C++ committee members to push breaking changes into the ISO-governed standard...
|
||||
I don't think it's feasible by any means.
|
||||
|
||||
Old people get older, and C++ software is becoming ancient history.
|
||||
The new generation is not interested in supporting no legacy code unless well-well-paid.
|
||||
What is happening with COBOL now is C++'s inevitable future.
|
||||
|
||||
C++ is a pile of poor ad-hoc Postel's law-governed design decisions and nomenclature, and it is not able to meet modern world requirements anymore.
|
||||
<s>Viva la revolución!</s>
|
||||
|
||||
----
|
||||
|
||||
_The speaker is removed by medics while shouting out revolutionary slogans._
|
||||
_Another younger-looking gentleman steps onto the scene._
|
||||
|
||||
Ahem.
|
||||
As we can see, there is no point in spending time on implementing a C++ package manager, as it would never be standardized (unless you're a Microsoft), hence widely adopted.
|
||||
C++ itself would become history sooner than it happens.
|
||||
But you, a reader, can try it for yourself.
|
||||
I don't mind.
|
||||
|
||||
Let's move on.
|
||||
|
||||
#### A Rust Implementation
|
||||
|
||||
Implementing such a service for Rust is totally feasible.
|
||||
The ([upcoming](http://smallcultfollowing.com/babysteps/blog/2020/01/09/towards-a-rust-foundation/)) Rust Foundation would have total control over crates.io -- the de facto standard Rust package hosting platform.
|
||||
All they need to do is to implement the Algorithm.
|
||||
|
||||
With such a platform implemented, Rust the language would be free to introduce breaking changes.
|
||||
I'm not sure about whether the concept of editions should remain, though.
|
||||
But anyway.
|
||||
|
||||
Even if I, as an individual, manage to implement a crates.io on-demand competitor earlier than the Rust Foundation does, they will inevitably take over, [thanking me](https://keivan.io/the-day-appget-died/) for the beta-test of the idea.
|
||||
Therefore, there is no motivation for me to spend time on a crates.io competition.
|
||||
|
||||
Moreover, I've already stated above why I don't like the Rust language itself.
|
||||
Convincing Rust maintainers to satisfy my complaints in an already stabilized language is more challenging than standardizing a new one.
|
||||
|
||||
#### An Implementation
|
||||
|
||||
The same applies for Javascript with [recently РЁРёСЂРѕРєР-acquired NPM](https://github.blog/2020-03-16-npm-is-joining-github/) and my desire for a system programming language rather than... Javascript.
|
||||
|
||||
Big guys owning existing centralized package distribution platforms might try solving the Open Source sustainability problem with the source-on-demand model.
|
||||
Until then, no smaller company or individual would dare to implement a competitor, and the suffering continues.
|
||||
|
||||
But if I were to implement a new system programming language, I'd then have enough power to experiment with the model.
|
||||
Plus one point to justifying.
|
||||
|
||||
<!-- Is that a monopoly?
|
||||
Maybe it is.
|
||||
|
||||
EU headquarters are enraged by Facebook acquiring Instagram, but when a single company owns both GitHub and NPM, which effectively covers 80% of the world's software -- that's alright. -->
|
||||
|
||||
## On Standardization
|
||||
|
||||
Wikipedia does an excellent job of explaining how [standardization affects technology](https://en.wikipedia.org/wiki/Standardization#Effect_on_technology):
|
||||
|
||||
> Increased adoption of a new technology as a result of standardization is important because rival and incompatible approaches competing in the marketplace can slow or even kill the growth of the technology (a state known as market fragmentation).
|
||||
> The shift to a modularized architecture as a result of standardization brings increased flexibility, rapid introduction of new products, and the ability to more closely meet individual customer's needs.
|
||||
>
|
||||
> The negative effects of standardization on technology have to do with its tendency to restrict new technology and innovation.
|
||||
> Standards shift competition from features to price because the features are defined by the standard.
|
||||
> The degree to which this is true depends on the specificity of the standard.
|
||||
> Standardization in an area also rules out alternative technologies as options while encouraging others.
|
||||
|
||||
By "standardization" Wikipedia means a tedious ISO-grade standardization process spanned by years.
|
||||
What I'm proposing instead is <mark>an open specification process driven by the community and businesses</mark>.
|
||||
With that, a standard remains flexible, and changes to it are shipped frequently.
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
The [lack of need to maintain backwards compatibility](#impact-on-a-language) <mark>allows multiple major versions of a language standard to peacefully co-exist</mark>: more breaking changes are allowed for the language to stay modern.
|
||||
|
||||
A language standard presence removes the bus factor when only the ones currently working on the canonical implementation have a deep understanding of the language.
|
||||
|
||||
As a result, other implementations may appear, <mark>focusing on their own needs</mark>.
|
||||
For example, some company may need a compiler for their exotic target.
|
||||
|
||||
::: off
|
||||
|
||||
Take [Zig](https://ziglang.org/).
|
||||
Andrew has to work on [supporting many targets](https://ziglang.org/#Wide-range-of-targets-supported) at once.
|
||||
Instead, he could delegate the implementation job to someone else and focus on the language specification.
|
||||
This would speed up the maturing process.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
:::
|
||||
|
||||
Apart from standardizing the language itself, its ecosystem shall also be standardized, including package management.
|
||||
This would <mark>allow competing implementations to remain compatible</mark>, giving an end-user more freedom in choosing of right tooling.
|
||||
|
||||
If I _were_ working on a language, standardization would matter more than an implementation for me.
|
||||
|
||||
## Wrapping up
|
||||
|
||||

|
||||
|
||||
C++, Rust and others have their [fatal flaws](https://en.wikipedia.org/wiki/Not_invented_here), but I still want to use a higher-level system programming language.
|
||||
|
||||
I'm willing to attempt solving the Open-Source Sustainability problem.
|
||||
|
||||
Creating a new language and applying the source-on-demand model to its canonical package hosting platform from the very beginning implies a great chance of prosperity for the language and its ecosystem.
|
||||
|
||||
Standardization of the language and its ecosystem implies a greater selection of compatible implementations and tooling for the end-user.
|
||||
|
||||
With the language's ecosystem being adequately funded, the language itself stays flexible, allowing for breaking changes.
|
||||
A flexible language stays modern, forever.
|
||||
|
||||
Worths a shot, doesn't it?
|
||||
|
||||
## The New Beginnings
|
||||
|
||||
Finally, it's the time to proudly announce another language I've come up with, a utopia-grade solution to replace both C++ and Rust once and forever!
|
||||
|
||||
So, what are the goals defined for the new language?
|
||||
|
||||
* Developer friendliness:
|
||||
|
||||
* Have fundamental design with shared concepts and minimum exclusive cases to keep in mind.
|
||||
* Infer developer intentions as much as possible, unless ambiguous.
|
||||
* Guarantee safe, defined behaviour by default, but still provide tools to write and abstract away unsafe code when needed.
|
||||
* Provide human-friendly object abstractions such as classes, but also contain a number of essential math abstractions to be used when required.
|
||||
|
||||
* Tools for optimal performance.
|
||||
By default, the code written in this language would be suboptimal, but with right tooling it is possible to write perfectly optimized code and abstract it away.
|
||||
With that, a developer would not have to choose another language just because it's faster.
|
||||
The requirement implies:
|
||||
|
||||
* Access to raw machine instructions, i.e. inline assembly.
|
||||
|
||||
* Pointer arithmetic and alignment.
|
||||
|
||||
* Control over memory ordering.
|
||||
|
||||
* WYSIWYG in terms of clearly understanding what code would compile into.
|
||||
|
||||
* Absolute platform agnosticism with the generalization of instructions shared by different instruction sets.
|
||||
The languages should not know anything about operating systems, but common things like integer arithmetics should be abstracted into objects.
|
||||
Modern instructions should be addressed, such as tensors and [brain floats](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format).
|
||||
|
||||
* Long-term maintainability of programs written in the language.
|
||||
This includes problems of inheritance, function overloading and so on.
|
||||
|
||||
As it turned out, a strong foundation for the language is also needed for success.
|
||||
The foundation goals are:
|
||||
|
||||
* Standardize as much as possible, including:
|
||||
|
||||
* An implementation binary interface and capabilities.
|
||||
|
||||
* Package management.
|
||||
|
||||
* API documentation format.
|
||||
|
||||
* Provide proper funding for the ecosystem, including rewarding package authors.
|
||||
This is where the [source-on-demand](#source-on-demand) model could be applied.
|
||||
|
||||
----
|
||||
|
||||
Are you ready?
|
||||
|
||||
...
|
||||
|
||||
_Drum roll intensifies..._ 🥁
|
||||
|
||||
...
|
||||
|
||||
Meet **Onyx**, the programming language I've been working on for a pretty long time now!
|
||||
|
||||

|
||||
|
||||
> Onyx is a general-purpose statically typed programming language suitable both for application and system programming.
|
||||
|
||||
Onyx meets all of the goals listed above and even more with the upcoming Onyx Software Foundation.
|
||||
Read more about it in the next [Onyx Programming Language](/posts/2020-08-20-the-onyx-programming-language) article.
|
||||
|
||||
----
|
||||
|
||||
In this article, I've come to a conclusion that the world needs (yet) another system programming language with a solid foundation and funding of its ecosystem, which would potentially solve all the existing problems.
|
||||
|
||||
I have formulated the goals for the new language and its ecosystem and even began working on the implementation, which you can read about more in the [next article](/posts/2020-08-20-the-onyx-programming-language).
|
||||
982
posts/2020-08-20-the-onyx-programming-language.md
Normal file
@@ -0,0 +1,982 @@
|
||||
---
|
||||
title: The Onyx Programming Language
|
||||
location: Moscow, Russia
|
||||
templateEngineOverride: md
|
||||
excerpt: System programming seems to be much harder than application programming. Why is that and how to overcome this?
|
||||
cover: /public/img/onyx-logo-white-background.png
|
||||
ogType: article
|
||||
---
|
||||
|
||||
In the [previous article](/posts/2020-08-16-system-programming-in-2k20) I successfully justified my desire to build yet another system programming language.
|
||||
Unlike _others_, I want to do it right from the very beginning.
|
||||
Meet Onyx!
|
||||
|
||||
<h2>Table of Contents</h2>
|
||||
|
||||
${toc}
|
||||
|
||||
## The Onyx programming language
|
||||
|
||||

|
||||
|
||||
Onyx is a general-purpose statically typed programming language suitable both for application and system programming.
|
||||
|
||||
### Top-Down Features
|
||||
|
||||
Onyx syntax is inspired by **C-family** languages, such as Ruby, C++ and even <s>Rust</s> <small>I'm sorry</small>.
|
||||
|
||||
Onyx imposes robust **inference** mechanisms.
|
||||
The rule is generally "infer unless ambiguous", with meaningful defaults.
|
||||
|
||||
Onyx is a **memory-safe** language.
|
||||
There are multiple levels of enforced safety, with `unsafe` being the minimum safety level allowing for extreme optimizations.
|
||||
This opens great opportunities for powerful abstractions.
|
||||
|
||||
Unlike [_other_](https://www.rust-lang.org/){.secret-link} languages, Onyx treats **pointer arithmetic** as a first-class use-case, but with memory safety.
|
||||
The concept is expressed in raw but typed pointers containing a memory scope.
|
||||
For example, it is not possible to safely pass a local pointer to an outer scope.
|
||||
Moreover, pointers preserve low-level features like address spacing and alignment.
|
||||
|
||||
It is extremely easy to do **interoperability** in Onyx.
|
||||
Onyx is similar to C++ in this sense: C code is considered a part of the program (with minor differences), and it is simple to export Onyx code as a shared library.
|
||||
|
||||
Programs written in Onyx are **cross-platform** by default in the sense of that there are no target-dependent features in the language itself: no threading, no memory control.
|
||||
But fear not, thanks to powerful abstractions, these are likely to be already implemented by someone else!
|
||||
|
||||
Onyx introduces **powerful macros** written in Lua.
|
||||
It allows to re-use existing Lua code and have full access to the compilation context thanks to easy debugging with Lua.
|
||||
|
||||
Onyx has **<u>[simple-to-understand](https://twitter.com/vladfaust/status/1299116755596566528){.secret-link}</u> lifetime and moving** concepts naturally built into the language.
|
||||
Instead of fighting with a borrow checker, simply get an address of a variable: a compiler would not allow you to misuse it.
|
||||
|
||||
Classes may have a finalizer defined and thus have **automatic resource control**.
|
||||
|
||||
Onyx implements real **traits** as [composable units of behaviour](https://en.wikipedia.org/wiki/Trait_(computer_programming)) thanks to powerful function management tools like aliasing, implementation transferring, un-declaring and renaming.
|
||||
|
||||
Classes and traits together impose **object-oriented** capabilities of the language.
|
||||
|
||||
Onyx has a concept of **generics**.
|
||||
Specializations of generic types may have different members and evaluate delayed macros.
|
||||
Specializations of functions with generic arguments may return different values and also evaluate delayed macros.
|
||||
|
||||
Functions may be **overloaded** by arguments and return values.
|
||||
|
||||
Onyx has a concept of **annotations**, which may be applied to variables and functions.
|
||||
|
||||
The language defines a set of now-commonly used **arithmetic types**, including SIMD vectors, matrices and tensors, floating and fixed binary and decimal numbers, brain and tensor floats, ranges and ratios.
|
||||
|
||||
Onyx contains several **utility types**, such as unions, variants, tuples, anonymous structs, lambdas and runnable blocks of code.
|
||||
|
||||
Exceptions are designed to be truly **zero-cost** to enable exception flow in Onyx programs.
|
||||
|
||||
### Hello, world!
|
||||
|
||||
Let's jump into some code samples.
|
||||
This would give a brief overview of how Onyx programs look like.
|
||||
|
||||
This is a very basic program written in Onyx:
|
||||
|
||||
```text
|
||||
import "stdio.h"
|
||||
|
||||
# Outputs "Hello, world!"
|
||||
export int main() {
|
||||
final msg = "Hello, world!\0"
|
||||
unsafe! $puts(&msg as $char*)
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
In the example, a C header named `"stdio.h"` was imported into the Onyx program.
|
||||
Now Onyx is aware of assembly functions declared by this header.
|
||||
|
||||
Later on, one of these functions, `puts` is called directly from Onyx.
|
||||
An Onyx compiler can not give any safety guarantees about called assembly functions. Therefore the call must be wrapped in an `unsafe!` statement.
|
||||
|
||||
If something weird happens, a developer may simply `grep` the program source code for `unsafe!` statement to quickly narrow to potentially hazardous areas of code.
|
||||
|
||||
Imported entities are referenced with preceding `$` symbol to distinguish them from those declared in Onyx context.
|
||||
|
||||
The `final` statement defines a constant named `msg`.
|
||||
The type of `msg` is inferred to be `String<UTF8, 14>`, i.e. a [UTF-8](https://en.wikipedia.org/wiki/UTF-8)-encoded array of [code units](https://en.wikipedia.org/wiki/Code_unit) containing 14 elements.
|
||||
Note that this is not a pointer, but a real array, probably allocated on stack.
|
||||
|
||||
Then, the address of the `msg` constant is taken.
|
||||
The resulting object of taking an address would be `String<UTF8, 14>*lr0`, which is a shortcut to `Pointer<Type: String<UTF8, 14>, Scope: :local, Readable: true, Writeable: false, Space: 0>`.
|
||||
|
||||
Do not be intimidated, though!
|
||||
Thanks to inference, shortcuts and meaningful defaults, you'll rarely have to use full types.
|
||||
|
||||
The pointer to `msg` is then coerced to C type `char*`.
|
||||
Such coercion would be unsafe, and a compiler would typically panic.
|
||||
|
||||
However, the coercion is already within the unsafe context itself thanks to the wrapping `unsafe!` statement.
|
||||
No need to write `unsafe!` again.
|
||||
|
||||
The program above is normally compiled by an Onyx compiler, such as [`fnxc`](https://github.com/fancysofthq/fnxc), into an object file.
|
||||
The object file declares the exported `int main(void)` prototype, which must be pointed to at as an entry function by a system linker.
|
||||
Thankfully, this tedious operation is likely to be automatically handled by a higher-level build tool, such as [`fnx`](https://github.com/fancysofthq/fnx).
|
||||
|
||||
Note that Onyx does not have any implicit `__onyx_main` function, which effectively restricts non-trivial automatic static variable initialization and finalization.
|
||||
But in return, it makes the emitted code predictable and portable.
|
||||
|
||||
### Using a Standard Library
|
||||
|
||||
An Onyx compiler is not required to implement any sort of OS-dependent standard library.
|
||||
Instead, the standard library Standard is specified elsewhere (spoiler alert: by [the Onyx Software Foundation](#the-onyx-software-foundation)).
|
||||
|
||||
A standard library ought to be used as a typical package and required like any other from your code.
|
||||
Again, by default, an Onyx program does not depend on any OS-specific features.
|
||||
|
||||
The example above could be abstracted into this when using a standard library implementation:
|
||||
|
||||
```text
|
||||
require "std"
|
||||
|
||||
export void main() {
|
||||
let msg = "Hello, world!\0"
|
||||
|
||||
try
|
||||
Std.puts(&msg)
|
||||
catch
|
||||
Std.exit(1)
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
Now, the code is perfectly safe.
|
||||
Even passing of `&msg` is allowed, because `Std.puts` has an overload accepting a `String*cr`, i.e. a read-only pointer with _caller_ scope, and a pointer with _local_ scope may be safely cast to _caller_ scope upon passing to a function.
|
||||
This is where the full power of pointer scope harnesses!
|
||||
|
||||
Also note that `msg` is now a **variable** instead of a constant, as it is defined with `let` statement.
|
||||
Taking the address of `msg` would return `String<UTF8, 14>*lrw0`.
|
||||
Notice the `w` part?
|
||||
The pointer is now writeable.
|
||||
And it is perfectly legit to pass a writeable pointer as a read-only argument: it would be coerced down to a read-only pointer within the callee.
|
||||
|
||||
### Exceptions
|
||||
|
||||
We had to wrap the `Std.puts` call into the `try` block, as it could throw some system exception.
|
||||
The cause is that an `export`ed function must guarantee never to throw an exception, that's why we wrapped it.
|
||||
The `Std.exit` function is declared as `nothrow`, so we can leave it as-is.
|
||||
|
||||
But what if we wanted to inspect the backtrace of the possible exception?
|
||||
Well, the language Standard states that a backtrace object must implement the `Endful<Location>` trait.
|
||||
This is truncated source code of the trait:
|
||||
|
||||
```text
|
||||
struct Location
|
||||
val path : String*sr # A static pointer
|
||||
val row, col : UBin32
|
||||
end
|
||||
|
||||
trait Endful<T>
|
||||
decl push(value: T)
|
||||
decl pop() : T
|
||||
decl pop?() : T?
|
||||
end
|
||||
```
|
||||
|
||||
Let's implement some `Stack` type to hold the backtrace.
|
||||
|
||||
::: spoiler ⚠️ A big chunk of non-trivial code!
|
||||
|
||||
```text
|
||||
# A stack growing upwards in memory.
|
||||
#
|
||||
# The `~ %n` part means "accept a natural
|
||||
# number literal as a generic argument".
|
||||
class Stack<Type: T, Size: Z ~ %n>
|
||||
# This class derives from this trait.
|
||||
derive Endful<T>;
|
||||
|
||||
# Define two empty structs.
|
||||
struct Overflow;
|
||||
struct Underflow;
|
||||
|
||||
# Do not finalize this variable
|
||||
# in the end of stack lifetime.
|
||||
#
|
||||
# `@[NoFinalize]` is application
|
||||
# of an unsafe annotation.
|
||||
unsafe! @[NoFinalize]
|
||||
final array = unsafe! uninitialized T[Z]
|
||||
|
||||
# A getter makes the variable read-only
|
||||
# from outside, but writeable inside.
|
||||
get size : Size = 0
|
||||
|
||||
# A class, unlike a struct, does
|
||||
# not have a default initializer.
|
||||
def initialize();
|
||||
|
||||
# But class allows to
|
||||
# define a finalizer!
|
||||
def finalize()
|
||||
# Only those stack elements which
|
||||
# are alive shall be finalized.
|
||||
size.times() -> unsafe! @finalize(array[&])
|
||||
end
|
||||
|
||||
# Push a value into the stack.
|
||||
# Throws in case of stack overflow.
|
||||
# It implements `Endful<T>:push`.
|
||||
impl push(val)
|
||||
# The scary operator is expanded to
|
||||
# `size <<= size ^+ 1`, meaning
|
||||
# "push-assign to `size` a saturated
|
||||
# sum of it with 1".
|
||||
#
|
||||
# Push-assignment returns the old
|
||||
# value instead of the new one.
|
||||
if (size ^+<<= 1) < Z
|
||||
# `<<-` moves the value from `val`
|
||||
# into the array, "ejecting" the
|
||||
# old array value. But at this point,
|
||||
# the old array value is already
|
||||
# finalized, so we explicitly disable
|
||||
# it finalization here.
|
||||
unsafe!
|
||||
@nofinalize(array[size - 1] <<- val)
|
||||
end
|
||||
else
|
||||
throw Overflow()
|
||||
end
|
||||
end
|
||||
|
||||
# Pop a value from the stack.
|
||||
# Throws in case of stack underflow.
|
||||
#
|
||||
# Note the alternative syntax to
|
||||
# reference the declaration.
|
||||
impl ~Endful<T>:pop()
|
||||
return pop?() ||
|
||||
throw Underflow()
|
||||
end
|
||||
|
||||
# Pop a value from the stack
|
||||
# if it is not empty.
|
||||
# Returns `Void` otherwise.
|
||||
impl nothrow pop?()
|
||||
# Expands to `size <<= size ^- 1`.
|
||||
if size ^-<<= 1 > 0
|
||||
# We don't copy the array element,
|
||||
# but move it from the array.
|
||||
#
|
||||
# A copy of bytes of the element are
|
||||
# preserved in the array, but we
|
||||
# consider it already dead, a corpse.
|
||||
#
|
||||
# That's why we don't finalize it
|
||||
# in the `push` implementation.
|
||||
return unsafe! <-array[size]
|
||||
else
|
||||
return Void
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Oof, sorry for such a seemingly complex piece of code.
|
||||
But I had to do it, sooner or later!
|
||||
|
||||
:::
|
||||
|
||||
But wait!
|
||||
Thankfully, the language already comes with a `Stack` implementation, so we don't need to write it in our code.
|
||||
|
||||
A `try` statement has optional `with` clause accepting a pointer to a `Endful<Location>` implementation.
|
||||
The example above may be rewritten like this:
|
||||
|
||||
```text
|
||||
require "std"
|
||||
|
||||
export void main() {
|
||||
let msg = "Hello, world!\0"
|
||||
final backtrace = Stack<Location, 32>()
|
||||
|
||||
try with &backtrace
|
||||
Std.puts(&msg)
|
||||
catch
|
||||
while final loc = backtrace.pop?()
|
||||
# Could've also made use of
|
||||
# `loc.row` and `loc.col`...
|
||||
Std.puts(loc.path)
|
||||
end
|
||||
catch
|
||||
# An unrecoverable error ☹️
|
||||
Std.exit(1)
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
Now we can inspect the exception backtrace!
|
||||
|
||||
### An HTTP Server Example
|
||||
|
||||
It is considered a good tone to demonstrate how to build a simple echoing HTTP web server in your language.
|
||||
This would also be my "sorry" for the big-ass `Stack` implementation above.
|
||||
|
||||
The thing is that running a web server is architecturally different on different target platforms.
|
||||
An implementation on Linux could make use of raw sockets, an implementation on Windows could make use of the win32 `"http.h"` header etc.
|
||||
|
||||
Therefore, the standard library would not contain a web server implementation.
|
||||
Instead, some third-party package should be used, which would inevitably be plenty of!
|
||||
|
||||
Let's imagine we've found one satisfying our needs.
|
||||
That's how it could look like:
|
||||
|
||||
```text
|
||||
require "std"
|
||||
require "http" from "mypkg"
|
||||
|
||||
export int main () {
|
||||
final backtrace = Stack<Location, 32>()
|
||||
|
||||
try with &backtrace
|
||||
final server = HTTP::Server()
|
||||
|
||||
server.get("/") ~> do |env|
|
||||
# Read the request into a
|
||||
# local `Std::Twine` instance.
|
||||
final body = env.request.read()
|
||||
|
||||
# Write the twine
|
||||
# into the response.
|
||||
env.response << body
|
||||
end
|
||||
|
||||
server.listen("localost", 3000)
|
||||
catch |e|
|
||||
Std.puts("Caught \@{{ e }}\n")
|
||||
|
||||
while final loc = backtrace.pop?()
|
||||
Std.cout << "At " <<
|
||||
loc.path << ":" <<
|
||||
loc.row << ":" <<
|
||||
loc.col << "\n"
|
||||
end
|
||||
|
||||
Std.exit(1)
|
||||
catch
|
||||
# Unrecoverable error 👿
|
||||
Std.exit(2)
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
Thanks to powerful abstractions and type inference, you won't need to manually use `socket` each time you want to spin up a web server on Linux!
|
||||
|
||||
Oh, by the way, did you notice the `\@{{ e }}` thing?
|
||||
It was me, <s>Dio</s> macro!
|
||||
|
||||
### Macros
|
||||
|
||||
A fundamental feature of Onyx is macros.
|
||||
Macro is a Lua code generating Onyx code (or another macro code).
|
||||
Yes, recursive macros are allowed, but more on that later.
|
||||
|
||||
Let's examine a straightforward macro example.
|
||||
|
||||
```text
|
||||
import "stdio.h"
|
||||
|
||||
export void main() {
|
||||
{% for i = 0, 2 do %}
|
||||
unsafe! $puts("i = {{ i }}")
|
||||
{% end %}
|
||||
}
|
||||
```
|
||||
|
||||
The code above would expand **exactly** to:
|
||||
|
||||
```text
|
||||
import "stdio.h"
|
||||
|
||||
export void main() {
|
||||
unsafe! $puts("i = 0")
|
||||
unsafe! $puts("i = 1")
|
||||
unsafe! $puts("i = 2")
|
||||
end
|
||||
```
|
||||
|
||||
That simple: the Lua code runs during compilation.
|
||||
And this is not some truncated version of Lua, no.
|
||||
This is a fully-fledged dynamic language, right within your compilation context.
|
||||
Think of reading and parsing files during compilation, accessing system configuration...
|
||||
The possibilities are endless.
|
||||
|
||||
You may concern about the safety of macros.
|
||||
Well, yes, you have to trust the code you run.
|
||||
You do trust C libraries you link to your programs, right?
|
||||
|
||||
However, you won't trust an NPM package, because an NPM package author does not care about their reputation, and because NPM does not have auditing features.
|
||||
This is the Open-Source sustainability problem addresses in the [previous article]((/posts/2020-08-16-system-programming-in-2k20)) and potentially solved by the aforementioned [Onyx Software Foundation](#the-onyx-software-foundation).
|
||||
|
||||
As a result, given that you do have access to code you require, authors of packages your program depends on are appropriately rewarded for their work, and the Foundation sponsors audition of selected packages, you should be safe.
|
||||
|
||||
----
|
||||
|
||||
Back to the possibilities.
|
||||
Macro use-cases include:
|
||||
|
||||
::: hero
|
||||
|
||||
**Delegating computations to compile-time**
|
||||
|
||||
:::
|
||||
|
||||
For example, you can compute a Fibonacci number sequence in a macro, and output the result right into the code.
|
||||
Let's examine the following small snippet:
|
||||
|
||||
```text
|
||||
{%
|
||||
-- Local context is preserved
|
||||
-- during this file compilation
|
||||
local function fib(n)
|
||||
local function inner(m)
|
||||
if m < 2 then
|
||||
return m
|
||||
end
|
||||
|
||||
return inner(m - 1) + inner(m - 2)
|
||||
end
|
||||
|
||||
return inner(n)
|
||||
end
|
||||
%}
|
||||
|
||||
# This is a macro "function", which
|
||||
# may be used directly from Onyx code.
|
||||
macro @fib(n)
|
||||
{{ fib(n) }}
|
||||
end
|
||||
|
||||
import "stdio.h"
|
||||
|
||||
export void main() {
|
||||
unsafe! $printf(&"%d\n", @fib(10))
|
||||
end
|
||||
```
|
||||
|
||||
In this example, `@fib(10)` would evaluate during compilation and emit a number literal `55`, so the code turns into simple `$printf(&"%d\n", 55)`.
|
||||
|
||||
Of course, this would increase compilation times, and it is your responsibility to find the right balance based on your needs.
|
||||
|
||||
----
|
||||
|
||||
::: hero
|
||||
|
||||
**Generating ORM models from SQL migration files**
|
||||
|
||||
:::
|
||||
|
||||
This is how it might look like:
|
||||
|
||||
```text
|
||||
macro @gen_class(name)
|
||||
{%
|
||||
-- Accessing system configuration
|
||||
local db_path = os.getenv("DB_PATH")
|
||||
|
||||
-- Builds "create_user" for "user.nx" file.
|
||||
-- Note that `name` variable is accessible.
|
||||
local migration_file_path =
|
||||
db_path .. "/create_" ..
|
||||
name.value .. ".sql"
|
||||
|
||||
-- Requiring works as usual, so you may
|
||||
-- make use of Lua packages, even those
|
||||
-- with native C bindings!
|
||||
local myparser = require("src/sqlorm.lua")
|
||||
|
||||
-- Begin emitting Onyx code
|
||||
nx.emit("class User\n")
|
||||
|
||||
-- Emit a field defintion per column parsed
|
||||
local function callback(field) do
|
||||
nx.emit("let " .. field.name ..
|
||||
" : " .. field.type .. "\n")
|
||||
end
|
||||
|
||||
myparser.parse(
|
||||
migration_file_path,
|
||||
callback)
|
||||
|
||||
nx.emit("end")
|
||||
%}
|
||||
end
|
||||
```
|
||||
|
||||
And then in some `model/user.nx` file:
|
||||
|
||||
```text
|
||||
# Require the file
|
||||
# containing the macro
|
||||
require "gen_class"
|
||||
|
||||
@gen_class("user")
|
||||
```
|
||||
|
||||
Which would possibly result in:
|
||||
|
||||
```text
|
||||
require "gen_class"
|
||||
|
||||
class User
|
||||
let name : String<UTF8, 128>
|
||||
let age : UBin8
|
||||
end
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
::: hero
|
||||
|
||||
**Generating code based on current compilation target**
|
||||
|
||||
:::
|
||||
|
||||
Nuff said.
|
||||
For example:
|
||||
|
||||
```text
|
||||
{% if nx.target.isa.id == "amd64" then %}
|
||||
$printf("This is amd64")
|
||||
{% else %}
|
||||
$printf("This is not amd64")
|
||||
{% end %}
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
::: hero
|
||||
|
||||
**Having different traits for different specializations**
|
||||
|
||||
:::
|
||||
|
||||
For example, there is `Int<Base: ~ \%n, Signed: ~ \%b, Size: ~ \%n>` type in the Core API representing an integer.
|
||||
|
||||
Based on the value of `Base` and `Signed` generic arguments, the actual code generated for, say, summation function, would call for different instructions for signed and unsigned integers.
|
||||
|
||||
It may look like this:
|
||||
|
||||
```text
|
||||
reopen Int<Base: 2, Signed: S, Size: Z> forall S, Z
|
||||
impl ~Real:add(another : self) throws Overflow
|
||||
final result = unsafe! uninitialized self
|
||||
final overflowed? = unsafe! uninitialized Bit
|
||||
|
||||
\{%
|
||||
local s = nx.scope.S.val and "s" or "u"
|
||||
local t = "i" .. nx.scope.Z.val
|
||||
%}
|
||||
|
||||
unsafe! asm
|
||||
template llvm
|
||||
%res = call {\{{ t }}, i1} @llvm.\{{ s }}add.\
|
||||
with.overflow.\{{ t }}(\{{ t }} $0, \{{ t }} $1)
|
||||
$2 = extractvalue {\{{ t }}, i1} %res, 1
|
||||
in r(this), r(another)
|
||||
out =r(overflowed?)
|
||||
end
|
||||
|
||||
if overflowed?
|
||||
throw Overflow()
|
||||
else
|
||||
unsafe! asm
|
||||
template llvm
|
||||
$0 = extractvalue {\{{ t }}, i1} %res, 0
|
||||
out =r(result)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
This is a fairly complex example making use of the inline assembly feature.
|
||||
But this is what the language is capable of.
|
||||
|
||||
Notice that delayed macro blocks, i.e. those beginning with `{{`, are evaluated on every specialization, so the contents of the `add` function would be different for `Int<Base: 2, Signed: true, Size: 16>` (a.k.a. `SBin16`) and `Int<Base: 2, Signed: false, Size: 32>` (a.k.a. `UBin32`).
|
||||
|
||||
There were other features of Onyx mentioned in the example: 1) reopening certain or broad (the `forall` thing), specializations, 2) aliasing.
|
||||
In fact, this is how integer aliasing looks like in the Core API:
|
||||
|
||||
```text
|
||||
# `IBin8` and `Bin8` are
|
||||
# both binary integer types.
|
||||
alias IBin<*>, Bin<*> = Int<2, *>
|
||||
|
||||
# Use a macro to DRY the code.
|
||||
private macro @alias_binary_sizes(id)
|
||||
alias \{{ id }}8 = \{{ id }}<8>
|
||||
alias \{{ id }}16 = \{{ id }}<16>
|
||||
alias \{{ id }}32 = \{{ id }}<32>
|
||||
alias \{{ id }}64 = \{{ id }}<64>
|
||||
alias \{{ id }}128 = \{{ id }}<128>
|
||||
end
|
||||
|
||||
# Signed binary integers.
|
||||
alias SIBin<*>, SBin<*> = IBin<true, *>
|
||||
@alias_binary_sizes("SIBin")
|
||||
@alias_binary_sizes("SBin")
|
||||
|
||||
# Unsigned binary integers.
|
||||
alias UIBin<*>, UBin<*> = IBin<false, *>
|
||||
@alias_binary_sizes("UIBin")
|
||||
@alias_binary_sizes("UBin")
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
Macro code can generate other macro code.
|
||||
The algorithm is to evaluate immediate macros (e.g. `{% %}`) immediately once they are met in the code by some lexer, but evaluate delayed macros (e.g. `\{% %}`) only when the time is right, for example, per specialization.
|
||||
|
||||
Apart from simply `print "Debug"`, Lua contains powerful debugging facilities, e.g. `debug()`.
|
||||
This means that you can debug your compilation, even with breakpoints from an IDE!
|
||||
|
||||
### Complex Types
|
||||
|
||||
Onyx type system comprises two types of an object: real and imaginary. Hence the name "complex".
|
||||
|
||||
Real type is the actual type with a concrete memory layout, while the imaginary type is how a compiler traits this object.
|
||||
|
||||
Together with trait types, this approach meets the maintainability goal [set](/posts/2020-08-16-system-programming-in-2k20/#the-new-beginnings) in the previous article.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```text
|
||||
trait Drawable2D
|
||||
decl draw()
|
||||
end
|
||||
|
||||
struct Point
|
||||
derive Drawable2D
|
||||
impl draw()
|
||||
# Draw the point
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
struct Line
|
||||
derive Drawable2D
|
||||
impl draw()
|
||||
# Draw the line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def do_draw(x ~ Drawable2D)
|
||||
x.draw()
|
||||
end
|
||||
```
|
||||
|
||||
Within the `do_draw` function `x` initially has type `Undef~Drawable2D`, where `Undef` is the real type, and `Drawable2D` is the imaginary type.
|
||||
|
||||
Having an `Undef` real type in an argument declaration implies that this argument is generic.
|
||||
In other words, for each unique real type specialization of `x`, the function would specialize once again.
|
||||
|
||||
Let's modify the function a bit:
|
||||
|
||||
```text
|
||||
def do_draw(x ~ Drawable2D)
|
||||
{% print("Immediate: " ..
|
||||
nx.ctx.x.real_type:dump()) %}
|
||||
|
||||
\{% print("Specialized: " ..
|
||||
nx.ctx.x.real_type:dump()) %}
|
||||
end
|
||||
|
||||
do_draw(Point())
|
||||
do_draw(Line())
|
||||
```
|
||||
|
||||
The compiler would output the following:
|
||||
|
||||
```text
|
||||
Immediate: Undef
|
||||
Specialized: Point
|
||||
Specialized: Line
|
||||
```
|
||||
|
||||
We can see that `Undef` specialized into a concrete type in a function specialization.
|
||||
|
||||
Would `x.draw()` work within such a function?
|
||||
Indeed it would because the imaginary type is set to `Drawable2D`.
|
||||
In other words, `x` has **behaviour** of `Drawable2D` and thus can be called its methods upon.
|
||||
|
||||
It is still possible to operate on a real type in this case thanks to type information known at compile-time:
|
||||
|
||||
```text
|
||||
def do_draw(x ~ Drawable2D)
|
||||
\{% if nx.ctx.x.real_type == nx.lkp("Point") %}
|
||||
# x : Point # Panic! It is still `Undef`
|
||||
# x.point_specific_method # Panic!
|
||||
(unsafe! x as Point).point_specific_method
|
||||
\{% end %}
|
||||
end
|
||||
```
|
||||
|
||||
`x.point_specific_method` would cause compiler panic, because it can not guarantee that this would work for every possible x **now and in the future**.
|
||||
This solves the potential issue when calling `do_draw` with a new type unexpectedly breaks the callee; in other words, incapsulation is preserved.
|
||||
|
||||
The language contains some syntax sugar to simplify the example above:
|
||||
|
||||
```text
|
||||
def do_draw(x ~ Drawable2D)
|
||||
if x is? Point
|
||||
x : Point # OK
|
||||
x.point_specific_method
|
||||
end
|
||||
|
||||
# # For the sake of scope incapsulation,
|
||||
# # can not do that outside of the branch.
|
||||
# x.point_specific_method # Panic!
|
||||
end
|
||||
```
|
||||
|
||||
Imagine that we add another trait with the same declared function.
|
||||
It Onyx, the collision must be resolved, but the collided functions can still be called by their original names after restricting the caller's imaginary type.
|
||||
For example:
|
||||
|
||||
```text
|
||||
trait Drawable3D
|
||||
decl draw()
|
||||
end
|
||||
|
||||
reopen Point
|
||||
derive Drawable3D
|
||||
impl draw() as draw3d
|
||||
# Draw point in 3D
|
||||
end
|
||||
end
|
||||
|
||||
# Move the existing implementation
|
||||
# under another name
|
||||
moveimpl ~Drawable2D:draw() to draw2d
|
||||
end
|
||||
```
|
||||
|
||||
Luckily, no changes have to be made to the `do_draw()` function, because the compiler treats the argument solely as `Drawable2D`, and calling `draw()` on it always calls `Drawable2D:draw()`!
|
||||
Again, changing the type from outside would not break a callee.
|
||||
Incapsulation at its finest!
|
||||
|
||||
### More Highlights
|
||||
|
||||
Some more highlights of the language's features:
|
||||
|
||||
* SIMD vectors and matrices built-in with literals.
|
||||
It looks like this:
|
||||
|
||||
```text
|
||||
let vec = <1, 2, 3, 4>
|
||||
vec : Vector<SBin32, 4>
|
||||
|
||||
# Note: `0` means row-
|
||||
# oriented matrix
|
||||
let mat = |[1, 2], [3, 4]|r
|
||||
mat : Matrix<SBin32, 2, 2, 0>
|
||||
```
|
||||
|
||||
In fact, `Vector` and `Matrix` are specializations of a more general `Tensor` type.
|
||||
|
||||
```text
|
||||
primitive Tensor<
|
||||
Type: T,
|
||||
Dimensions: *D ~ \%n,
|
||||
Leading: L ~ \%n>;
|
||||
|
||||
alias Matrix<
|
||||
Type: T,
|
||||
Rows: R ~\%n,
|
||||
Cols: C ~\%n,
|
||||
Leading: L ~ \%n
|
||||
> = Tensor<T, R, C, L>
|
||||
|
||||
alias Vector<
|
||||
Type: T,
|
||||
Size: Z
|
||||
> = Tensor<T, Z, 0>
|
||||
```
|
||||
|
||||
* "Magic" literals inspired by Ruby:
|
||||
|
||||
```text
|
||||
let vec = %i<1 2 3 4>
|
||||
let mat = %i|[1 2][3 4]|r
|
||||
let ary = %f64[1 2 3]
|
||||
```
|
||||
|
||||
* [IEC](https://en.wikipedia.org/wiki/Kibibyte) and [SI](https://en.wikipedia.org/wiki/Kilobyte) numerical literal prefixes:
|
||||
|
||||
```text
|
||||
# Kibi
|
||||
@assert(42Ki == 43_008)
|
||||
|
||||
# Femto
|
||||
@assert(42ff64 ~=
|
||||
0.000_000_000_000_042)
|
||||
|
||||
# Mega and milli
|
||||
@assert(42M.17mf64 ~=
|
||||
42_000_000.017)
|
||||
```
|
||||
|
||||
* String and character literals with default UTF-8 encoding and UCS charset.
|
||||
The language allows custom string and character literal suffixes for custom encodings.
|
||||
|
||||
```text
|
||||
final u8 = "Привет, мир!"
|
||||
u8 : String<UTF8, 21>
|
||||
@assert(@sizeof(u8) == 21)
|
||||
|
||||
final u16 = "Привет, мир!"utf16le
|
||||
u16 : String<UTF16LE, 24>
|
||||
@assert(@sizeof(u16) == 24)
|
||||
|
||||
# ASCII-US is NOT a built-in encoding
|
||||
final ascii = "Hello, world!"asciius
|
||||
ascii : String<ASCII, 13>
|
||||
@assert(@sizeof(ascii) == 13)
|
||||
|
||||
final c = 'ф'
|
||||
c : Char<UCS>
|
||||
@assert(@sizeof(c) == 4)
|
||||
```
|
||||
|
||||
* Distinct aliasing allows having a type with different methods, but the same layout.
|
||||
For example, the `String` type is a distinct alias to an array of codeunits:
|
||||
|
||||
```text
|
||||
distinct alias String<
|
||||
Encoding: E,
|
||||
Size: Z
|
||||
> = Array<Codeunit<E>, Z>
|
||||
# This method is only declared
|
||||
# for strings, not arrays.
|
||||
decl get_char(position : UBin32)
|
||||
end
|
||||
```
|
||||
|
||||
* `Any` real type implies a variant of all possible types.
|
||||
In practice, it is often constrained by an imaginary type to reduce the number of contained options and define behaviour.
|
||||
For example:
|
||||
|
||||
```text
|
||||
trait Logger
|
||||
decl log()
|
||||
end
|
||||
|
||||
class Processor
|
||||
# Stores a variant of all possible
|
||||
# `Logger` implementations.
|
||||
let logger : Any~Logger
|
||||
|
||||
def process()
|
||||
# This is still any logger
|
||||
logger : Any~Logger
|
||||
|
||||
# Thanks to its imaginary type,
|
||||
# can call the declared method
|
||||
logger.log()
|
||||
end
|
||||
end
|
||||
|
||||
struct MyLogger
|
||||
derive Logger
|
||||
impl log()
|
||||
# Some implementation
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
I could continue digging into Onyx features and examples, but for an introductory post, that should be enough.
|
||||
|
||||
However, a good language by itself is only a half successful endeavour.
|
||||
Any new language needs a good foundation, ensuring the growth of its ecosystem.
|
||||
This is where the Onyx Software Foundation comes into play.
|
||||
|
||||
## The Onyx Software Foundation
|
||||
|
||||
The Onyx Software Foundation ([NXSF](https://nxsf.org)) is to be an official 501 \(c\) non-profit organization, so donations made to it are tax-exemptive.
|
||||
|
||||
All NXSF processes are going to be transparent and open.
|
||||
|
||||
### Standards
|
||||
|
||||
The Foundation will be governing several major and auxiliary standard specifications related to Onyx:
|
||||
|
||||
1. [The Onyx Programming Language Specification](https://github.com/nxsf/onyx).
|
||||
The specification includes the following:
|
||||
|
||||
1. Language specification, including macro API specification.
|
||||
|
||||
1. Platform identifiers specification.
|
||||
For example, `amd64`, not `x86_64`.
|
||||
The list includes [ISA](https://en.wikipedia.org/wiki/Instruction_set_architecture)s with meaningful default <abbr title="Instruction Set Extensions">ISE</abbr>s, modern processing units list (e.g. `skylake`) with set of enables ISEs for them, operating systems and ABIs.
|
||||
|
||||
1. Portable API format informative specification.
|
||||
So that raw API documentation generated by a compiler may be used by different documentation visualizers.
|
||||
|
||||
1. Expected optimizations informative specification.
|
||||
So a user may safely rely on compiler optimizations, e.g. loop unrolling.
|
||||
|
||||
1. The Onyx Standard Library Package Specification.
|
||||
Basically, a set of declarations which standard library package implementations shall obey.
|
||||
|
||||
1. The Onyx Package Management Specification.
|
||||
Defines client and server side APIs for relieable package acquisition.
|
||||
This includes versioning algorithms and, for example, requiring third-party auditions.
|
||||
|
||||
1. The Onyx Compiler Interface Specification.
|
||||
So different compiler implementations had a unified interface to interact with, using DSON.
|
||||
|
||||
1. [Dead-Simple Object Notation (DSON) Specification](https://github.com/nxsf/dson).
|
||||
This format is intended to be used in CLI to describe complex object structures.
|
||||
|
||||
1. [DSON Schema Specification.](https://github.com/nxsf/dson-schema)
|
||||
The standard to describe objects in DSON.
|
||||
|
||||
Standardization process will be official, with responsible committees consisting of community-elected members called _community champions_, and businesses sponsoring the Foundation.
|
||||
The votes will be split evenly between community and businesses to represent both sides fairly.
|
||||
|
||||
### Package Hosting
|
||||
|
||||
NXSF will provide a free Onyx package hosting platform.
|
||||
|
||||
To be eligeble for hosting, a package shall have an OSI-approved license.
|
||||
|
||||
NXSF will provide funding for packages both based on the [source-on-demand](/posts/2020-08-16-system-programming-in-2k20/#source-on-demand) model and selectively chosen by a Foundation committee.
|
||||
|
||||
In addition to monetary funding, NXSF would also sponsor recurring security auditions of selected packages.
|
||||
|
||||
### Funding the Ecosystem
|
||||
|
||||
Apart from funding packages, the Foundation will sponsor projects and events related to Onyx, including teaching conferences, teaching materials, integrations etc.
|
||||
|
||||
----
|
||||
|
||||
Onyx is the perfect balance between productivity and performance, a language understandable well both by humans and machines.
|
||||
|
||||
Thanks to powerful abstraction mechanisms and inference, the areas of the appliance are truly endless.
|
||||
I heartfully believe that Onyx may become a new lingua franca for decades until humanity learns to transfer thoughts directly into machines.
|
||||
|
||||
Visit [nxsf.org](https://nxsf.org) to stay updated, and...
|
||||
|
||||
----
|
||||
|
||||
::: hero
|
||||
|
||||
<big>Enjoy the performance.</big>
|
||||
|
||||
:::
|
||||
|
||||
----
|
||||
|
||||
P.S: Until the Foundation is officially established, you may consider [sponsoring me directly](/posts/2020-08-27-sponsoring-onyx/) and joining the conversation on the [forum](https://forum.onyxlang.com).
|
||||
239
posts/2020-08-27-sponsoring-onyx.md
Normal file
@@ -0,0 +1,239 @@
|
||||
---
|
||||
title: Sponsoring Onyx
|
||||
location: Moscow, Russia
|
||||
excerpt: Standardizing and implementing a system programming language is hard, but you can help!
|
||||
cover: /public/img/posts/2020-08-27-sponsoring-onyx/i-need-healing.jpg
|
||||
ogType: article
|
||||
---
|
||||
|
||||
Standardizing and implementing a system programming language is hard, but you can help!
|
||||
Find out how you can sponsor the future, and how many hours does it take to create a language mascot, in this post.
|
||||
|
||||
<h2>TL; DR;</h2>
|
||||
|
||||
I wAnT yOuR mOnEy! 🤑
|
||||
Pledge to my will on [Patreon](https://www.patreon.com/vladfaust) or buy me a coffee at [BMC](https://www.buymeacoffee.com/vladfaust)! 😂😂😂
|
||||
|
||||
----
|
||||
|
||||
<h2>Table of Contents</h2>
|
||||
|
||||
${toc}
|
||||
|
||||
## Introduction
|
||||
|
||||
I've been working on the [Onyx programming language](/posts/2020-08-20-the-onyx-programming-language) full-time for the past year.
|
||||
The work includes standardization and implementation.
|
||||
The process is _near to completion_, and there is a substantial chance for you to write your name in history.
|
||||
|
||||
In this post, I'll try to justify my eager will to grab your money with some proof of work.
|
||||
|
||||
By the way, I assume you've read my recent [post on System Programming](/posts/2019-08-16-system-programming-in-2k20), there is a [section](/posts/2019-08-16-system-programming-in-2k20/#on-open-source-sustainability) regarding to the open-source sustainability; as long as all my work is open, I'm also, um, an open-source engineer and thus need financial support.
|
||||
|
||||
## Deeds Already Done
|
||||
|
||||
The onyxlang.org domain name was registered on June 20^th^ 2019.
|
||||
As I have a sin of registering domains as soon as I have a solid idea, the day may be treated as the Onyx birthday.
|
||||
|
||||
Today is August 27^th^ 2020, and I've already spent a plethora of time on Onyx.
|
||||
You can see it for yourself in [NXSF](https://github.com/nxsf) and [FancySoft](https://github.com/fancysofthq) organization repositories!
|
||||
|
||||
### Tracked Time
|
||||
|
||||
From June 20^th^ 2019 until August 27^th^ 2020, this is the total time I've spent on *coding* Onyx specification, reference(s) and implementation(s):
|
||||
|
||||
::: hero
|
||||
|
||||
<big>1043 hrs 34 mins</big>
|
||||
|
||||
:::
|
||||
|
||||
I've had hard _time_ on maintaining a single project across machines, so there is a lot of them (projects).
|
||||
You may click on a project's name to see a detailed timing per file.
|
||||
|
||||
_Due to WakaTime limitations, I have to split the periods._
|
||||
|
||||
From June 20^th^ 2019 until June 20^th^ 2020:
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
Project name | Time spent{style="width: 10rem"} | Notes
|
||||
--- | --- | ---
|
||||
[`onyx`](https://wakatime.com/@vladfaust/projects/hmfpxdoxna?start=2019-06-20&end=2020-06-20) | 362 hrs 28 mins | Three generations of compilers. There even was [one written in Lua](https://github.com/fancysofthq/fnxc/tree/762e945916aa23f128f82541dd68bd8b90ff74f4)!
|
||||
[`onyxlang`](https://wakatime.com/@vladfaust/projects/gbrlphmype?start=2019-06-20&end=2020-06-20) | 237 hrs 47 mins | The [Specification](https://github.com/nxsf/onyx)
|
||||
[`lang`](https://wakatime.com/@vladfaust/projects/vnqouuvero?start=2019-06-20&end=2020-06-20) | 109 hrs 25 mins | A mix of specification and references
|
||||
[`onyxsoftware`](https://wakatime.com/@vladfaust/projects/tjfynfxpvi?start=2019-06-20&end=2020-06-20) | 29 hrs 21 mins | Specification, again
|
||||
[`kaleidoscope`](https://wakatime.com/@vladfaust/projects/amomlfdyzs?start=2019-06-20&end=2020-06-20) | 25 hrs 32 mins | Well, I've been learning [how to fight dragons](https://github.com/vladfaust/kaleidoscope)!
|
||||
[`ref`](https://wakatime.com/@vladfaust/projects/vjnrvaqkxn?start=2019-06-20&end=2020-06-20) | 18 hrs 9 mins | Some reference
|
||||
[`reference`](https://wakatime.com/@vladfaust/projects/bcdesjivqi?start=2019-06-20&end=2020-06-20) | 15 hrs 10 mins | Duh
|
||||
[`onyxstd`](https://wakatime.com/@vladfaust/projects/swdwsydknq?start=2019-06-20&end=2020-06-20) | 14 hrs 45 mins | An attempt to implement a standard library... in Onyx
|
||||
[`onyxcontrib`](https://wakatime.com/@vladfaust/projects/jrjvmhlpps?start=2019-06-20&end=2020-06-20) | 10 hrs 7 mins | Some Onyx code like HTTP server implementation
|
||||
[`onyxc`](https://wakatime.com/@vladfaust/projects/qrrswxtxje?start=2019-06-20&end=2020-06-20) | 9 hrs 58 mins | Another work put in a compiler
|
||||
[`code`](https://wakatime.com/@vladfaust/projects/wzdrcnwxzr?start=2019-06-20&end=2020-06-20) | 9 hrs 29 mins | [The Visual Studio Code extension](https://github.com/fancysofthq/code)
|
||||
[`compiler`](https://wakatime.com/@vladfaust/projects/jvoarxevqx?start=2019-06-20&end=2020-06-20) | 7 hrs 36 mins | A compiler?
|
||||
**Total** | 849 hrs 2 mins |
|
||||
|
||||
</div>
|
||||
|
||||
From June 20^th^ 2020 until August 27^th^ 2020:
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
Project name | Time spent{style="width: 30%"} | Notes
|
||||
--- | --- | ---
|
||||
[`onyxlang`](https://wakatime.com/@vladfaust/projects/gbrlphmype?start=2020-06-20&end=2020-08-27) | 106 hrs 1 min | The [Specification](https://github.com/nxsf/onyx)
|
||||
[`nxc`](https://wakatime.com/@vladfaust/projects/rcdubvxegp?start=2020-06-20&end=2020-08-27) | 47 hrs 56 mins | The [C++ Compiler](https://github.com/fancysofthq/fnxc), finally
|
||||
[`onyx-quickref`](https://wakatime.com/@vladfaust/projects/oygjwrhlgt?start=2020-06-20&end=2020-08-27) | 19 hrs 29 mins | The "quick" [reference](https://github.com/fancysofthq/onyx-ref)
|
||||
[`onyx`](https://wakatime.com/@vladfaust/projects/hmfpxdoxna?start=2020-06-20&end=2020-08-27) | 14 hrs 31 mins | Mostly reference
|
||||
[`onyxlang.com`](https://wakatime.com/@vladfaust/projects/aeahlrpcbp?start=2020-06-20&end=2020-08-27) | 2 hrs 44 mins | The website
|
||||
[`quickref`](https://wakatime.com/@vladfaust/projects/oirloanfrd?start=2020-06-20&end=2020-08-27) | 2 hrs 42 mins | Also [reference](https://github.com/fancysofthq/onyx-ref)
|
||||
[`fancyx`](https://wakatime.com/@vladfaust/projects/ozhupbhlcw?start=2020-06-20&end=2020-08-27) | 1 hr 9 mins | Some parts of the C++ compiler
|
||||
**Total** | 194 hrs 32 mins |
|
||||
|
||||
</div>
|
||||
|
||||
### Untracked Time
|
||||
|
||||
One shall not forget that designing a language does not equal constantly slapping keyboard strokes.
|
||||
In fact, implementing before giving a good thought may lead to [tragic results](https://github.com/crystal-lang/crystal/labels/kind%3Abug).
|
||||
|
||||
 is the general sponsor of Onyx](../../../public/img/posts/2020-08-27-sponsoring-onyx/thinking-meme.jpg "A 'programming is mostly thinking' meme" =60%x)
|
||||
|
||||
I've destroyed several notebooks while deciding on either using `do` / `end` or tabs.
|
||||
<small>There has been a double of them throughout the year, but who's gonna believe in it?</small>
|
||||
Would you dare to calculate the number of sleepless hours I've spent on _thinking_?
|
||||
|
||||

|
||||

|
||||
|
||||
### Time Tracked in Real... Time
|
||||
|
||||
[WakaTime](https://wakatime.com/) is awesome, because it allows to embed recent coding statistics, so you can see how much I <s>wasted my youth</s> coded during the last 30 days!
|
||||
|
||||
<figure>
|
||||
<embed src="https://wakatime.com/share/@vladfaust/d2418af2-a022-4f64-ada1-05fede7619fd.svg"></embed>
|
||||
<figcaption>Coding activity in the last 30 days (updates daily)</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<embed src="https://wakatime.com/share/@vladfaust/e1ccdc24-0b8a-461e-8dd6-066a5f4220c9.svg"></embed>
|
||||
<figcaption>Languages used in the last 30 days (updates daily)</figcaption>
|
||||
</figure>
|
||||
|
||||
## Sponsoring the Development
|
||||
|
||||
So, the idea is simple: I want to be able to pay my bills while working on a thing both I enjoy working on and being useful for humanity.
|
||||
|
||||
Later on, I'm planning to make [NXSF](https://nxsf.org) an official 501 \(c\) non-profit organization, so donations made to it would be tax-exemptive, and I will have an official salary (_finally!_).
|
||||
However, this would only happen when the language moves to the alpha stage (see the roadmap at [nxsf.org](https://nxsf.org/)).
|
||||
|
||||
Right now, Onyx is in the pre-alpha stage.
|
||||
Nothing is publicly stable, work-in-progress etcetera.
|
||||
But I still need to pay my bills.
|
||||
And as I haven't got a real job for a long, long time, my financial cushion is relatively thin.
|
||||
|
||||
As a copyright holder, I'm planning on licensing the specifications I've been working on with a free, open-source license requiring attribution.
|
||||
|
||||
That said, I can offer you, a potential sponsor, a **perpetual**\* attribution in the Onyx programming language standard specification.
|
||||
Your name or company logo with an optional link will be put into the according Early Backers section of the Standard.
|
||||
|
||||
\* As long as my attribution is required.
|
||||
For example, if the Standard is rewritten from scratch by an NXSF committee without infringing my patent rights, it then stops being a derivation of my work.
|
||||
|
||||
### The Dark Scheme
|
||||
|
||||
According to the [roadmap](https://nxsf.org/), during the Pre-alpha stage no donations are accepted by NXSF.
|
||||
Instead, you can donate directly to me, Vlad Faust, as I am effectively being the single developer thereof.
|
||||
Note that these donations would not be tax-exemptive.
|
||||
|
||||
Also, note that the Pre-alpha stage implies no code contributions accepted officially.
|
||||
Of course, you're free to pitch your ideas informally (e.g. via [Twitter](https://twitter.com/vladfaust) or the [forum](https://forum.onyxlang.com)), but you will not have any voting rights in any of standards development during this time.
|
||||
|
||||
----
|
||||
|
||||
Donations made to me during this period accumulate, and the resulting sum defines the tier of your attribution.
|
||||
|
||||
1. From $25.
|
||||
You're attributed with your name in the Early Individual Backers section.
|
||||
|
||||
1. From $100.
|
||||
You're attributed with a custom link in the Early Individual Backers section.
|
||||
|
||||
1. From $500.
|
||||
Your company's logo and link are attributed in the Early Business Backers section.
|
||||
|
||||
Individual tier backers are listed separately from Business tier backers.
|
||||
|
||||
----
|
||||
|
||||
I also want to incentivize early backers, so the <s>pyramind</s> scheme is as follows.
|
||||
|
||||
I learned the hard way that estimating time on completing such a big project as a language specification is _quite_ hard.
|
||||
Nonetheless, I'm planning to move on to the alpha stage in **3-5 months** from today (August 27^th^ 2020).
|
||||
|
||||
The earlier you donate, the more belief you have in me, the more you shall be rewarded.
|
||||
And higher reward means **higher placement in the backers list**!
|
||||
|
||||
The placement of your attribution depends on your _donation score_, which is based on the amount you've donated.
|
||||
Each month from today until the alpha stage, the score multiplier is reduced proportionally.
|
||||
The multiplier stays the same for you throughout the months if you donate sequentially, i.e. without cancellations.
|
||||
|
||||
::: spoiler An example
|
||||
|
||||
Let's _imagine_ that alpha stage comes December 13^th^ 2020.
|
||||
That means that since September 1^st^ 2020, **3 full months** passed.
|
||||
The donations are made 1^st^ of each recurring month.
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
Month a donation was made | Donation score multiplier{style="width: 50%"}
|
||||
--- | ---
|
||||
September | `1`
|
||||
October | `(1 - 1/4) = 3/4`
|
||||
November | `(1 - 2/4) = 2/4`
|
||||
December | `(1 - 3/4) = 1/4`
|
||||
|
||||
</div>
|
||||
|
||||
If Jake began their sponsorship in September with $100 per month without cancellations, his final score would be `100 * 1 + 100 * 1 + 100 * 1 + 100 * 1 = 400`.
|
||||
|
||||
If John donated $100 once in October, then skipped November and donated the same $100 in December (as the hype grows), his final score would be `100 * (3 / 4) + 100 * (1 / 4) = 100`.
|
||||
|
||||
As a result, John's placement would be lower than Jake's in the backers list.
|
||||
|
||||
In case of argument, the day a donation was made matters: making a donation on 3^rd^ gives more score than on 5^th^.
|
||||
|
||||
:::
|
||||
|
||||
### My Soundcloud
|
||||
|
||||
You're welcome to become my patron on [Patreon](https://patreon.com/vladfaust) or buy me a coffee at [BuyMeACoffee](https://buymeacoffee.com/vladfaust).
|
||||
|
||||
Donations made on Patreon imply exclusive Forum and Discord roles, and Onyx Visioner merch.
|
||||
BMC donations do not have those benefits but can be smaller and one-time.
|
||||
Ideal if you want to just tip me a couple of times.
|
||||
|
||||
Direct Bitcoin donations are also accepted, but they are not eligible for listing.
|
||||
|
||||
### Everlasting Dev
|
||||
|
||||
I want to assure you that I have no long-term plans on living on these sponsorships.
|
||||
I'm neither a [YandereDev](https://knowyourmeme.com/memes/people/yanderedev) nor some [Alex Medvednikov](https://vlang.io/).
|
||||
The sponsorship opportunity is in effect exclusively during the pre-alpha stage.
|
||||
|
||||
Once the Foundation is established, you'll be guided to put your money there instead, in the form of donations, which implies tax exemption and proper voting rights.
|
||||
|
||||
[Fancy Software LLC](https://fancysoft.xyz) is a for-profit company and I as no other else want Onyx to be complete, so I can start working on my premium packages, self-hosted, gaming and AI products.
|
||||
No Patreon sponsorship or non-profit salary can buy me a house.
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
Until then, I want to be able to pay my bills and maybe purchase a newer graphics card.
|
||||
In return, you get a chance to be immortalized as a visioner invested in a better future.
|
||||
|
||||
Follow me on [Twitter](https://twitter.com/vladfaust) and [GitHub](https://github.com/vladfaust), join the conversation on the [forum](https://forum.onyxlang.com) and also follow [NXSF](https://nxsf.org/) and [FancySoft](https://fancysoft.xyz/) to stay updated about the progress made.
|
||||
|
||||
Oh yes, there is also an official (i.e. NXSF-governed) standard planned on the language's mascot.
|
||||
It will be a [panther-girl](https://en.wikipedia.org/wiki/Catgirl) named Onyx-chan. Nya! 🐾
|
||||
3
posts/posts.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"layout": "post.pug"
|
||||
}
|
||||
17
public/icon/cap.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg width="512" height="512" version="1.1" viewBox="0 0 61 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path id="Shape" d="m55.3 32.76c-0.82645-0.23448-1.5469-0.74655-2.04-1.45-1.42-2.12-4.83-3.74-6.71-4.51 0.59-0.21-0.01-3.38 0.39-3.76v-0.01c0.01511-0.01771 0.03676-0.02853 0.06-0.03 4.2-0.84 8.26 2.6 10.23 3.04h0.01c0.79753 0.63628 1.4807 1.404 2.02 2.27 2.3 3.83-1.27 5.31-3.96 4.45z" fill="#37474f"/>
|
||||
<path d="m18.27 29.82c-4.47 1.22-13.08 3.1-15.27 0.18 0 0 5.32-8.04 12-10 0.92 0.94 1.43 8.43 3.27 9.82z" fill="#37474f"/>
|
||||
<path d="m57.23 26.04c-1.8226-0.37067-3.6922-0.45166-5.54-0.24-4.09-3.18-10.66-4.49-10.66-4.49s-2.45-3.05-9.75-3.66c11.4-0.81 14.98 3.66 14.98 3.66s6.91 1.38 10.97 4.73z" fill="#cfd8dc"/>
|
||||
<path d="m51.69 25.8c-0.21 0.02-0.42 0.04-0.64 0.07-0.85 0.09-1.78 0.24-2.79 0.44-0.58134 0.12078-1.1529 0.28456-1.71 0.49-5.33 1.88-13.28 8.1-19.55 7.2-0.4-0.06-0.81-0.14-1.21-0.24-2.7384-0.81349-5.2924-2.1517-7.52-3.94-1.5089-1.1452-2.9327-2.3985-4.26-3.75 3.97-1.16 8.77-7.32 13.99-8.07 1.16-0.17 2.25-0.28 3.28-0.35 7.3 0.61 9.75 3.66 9.75 3.66s6.57 1.31 10.66 4.49z" fill="#f5f5f5"/>
|
||||
<path d="m52 26.04c-0.31319-0.07464-0.63037-0.13139-0.95-0.17 0.22-0.03 0.43-0.05 0.64-0.07 0.10755 0.0744 0.21104 0.15451 0.31 0.24z" fill="#707070"/>
|
||||
<path d="m46.26 21.31s-4.26-0.31-18.26 1.69c-4.7295 0.69449-9.4043 1.7203-13.99 3.07-3.7501 1.0738-7.4276 2.3865-11.01 3.93-0.16-0.39-0.3-0.77-0.43-1.16-4.37-12.95 4.4-26.27 19.28-27.16 2.0555-0.11825 4.1178-0.010946 6.15 0.32 19 3 18.26 19.31 18.26 19.31z" fill="#cfd8dc"/>
|
||||
<path d="m43 21.31s-4.26-0.31-18.26 1.69c-4.7295 0.69449-9.4043 1.7203-13.99 3.07-3.44 1.01-5.83 3.18-7.75 3.93-4.37-12.95 3.97-27.43 18.85-28.32 0.94 0.06 1.91 0.16 2.89 0.32 19 3 18.26 19.31 18.26 19.31z" fill="#f5f5f5"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="m3 31c-0.40919 1.5e-4 -0.77719-0.24901-0.929-0.629-2.9791-7.1199-1.8513-15.296 2.944-21.344 5.177-6.489 13.831-9.485 23.141-8.014 19.656 3.1 19.114 20.173 19.106 20.344-0.012 0.26955-0.13242 0.52282-0.33391 0.70228s-0.46695 0.26988-0.73609 0.25072c-0.057 0-4.431-0.265-18.05 1.68-8.5013 1.2556-16.81 3.5807-24.728 6.92-0.12999 0.059224-0.27116 0.089913-0.414 0.09zm20.409-28.368c-6.884 0-12.867 2.676-16.831 7.643-4.1221 5.1956-5.2599 12.155-3.007 18.393 7.8017-3.1786 15.955-5.4137 24.287-6.658 5.7557-0.93416 11.565-1.5053 17.392-1.71-0.185-3.458-1.971-14.87-17.406-17.308-1.4667-0.23535-2.9495-0.35572-4.435-0.36z"/>
|
||||
<path d="m28.277 35.089c-0.47478 4.65e-4 -0.94898-0.03295-1.419-0.1-2.816-0.406-5.908-1.878-9.193-4.374-1.5467-1.1756-3.0071-2.4606-4.37-3.845-0.3866-0.39461-0.38011-1.0279 0.0145-1.4145s1.0279-0.38011 1.4145 0.0145c1.2937 1.3152 2.6803 2.5356 4.149 3.652 2.3827 1.9955 5.2249 3.3661 8.27 3.988 3.938 0.575 8.822-2.028 13.135-4.316 1.9133-1.0809 3.899-2.0282 5.943-2.835 0.60392-0.2224 1.2237-0.39923 1.854-0.529 3.0665-0.73353 6.2516-0.82477 9.355-0.268 0.46922 0.0918 0.80781 0.50289 0.808 0.981-0.0059 0.30235-0.14607 0.58639-0.38244 0.77503-0.23637 0.18863-0.54443 0.26229-0.84056 0.20097-2.8405-0.49821-5.7532-0.40493-8.556 0.274-0.53394 0.11103-1.0588 0.26213-1.57 0.452-1.9507 0.77563-3.8464 1.6831-5.674 2.716-4.115 2.184-8.725 4.628-12.938 4.628z"/>
|
||||
<path d="m56.826 33.989c-1.7265 0.05965-3.3718-0.73384-4.4-2.122-0.925-1.381-3.2-2.889-6.257-4.138-0.33083-0.1354-0.56429-0.43702-0.61244-0.79122-0.04815-0.35421 0.09632-0.7072 0.379-0.926 0.28268-0.2188 0.66061-0.27018 0.99144-0.13478 2.448 1 5.677 2.662 7.162 4.879 1.0607 1.2494 2.8424 1.6033 4.3 0.854 0.809-0.511 0.813-1.448 0.012-2.783-0.46212-0.74261-1.0456-1.4024-1.726-1.952-0.02871-0.01887-0.05642-0.03923-0.083-0.061-3.822-3.154-10.463-4.507-10.53-4.521-0.53453-0.11481-0.87777-0.63761-0.7706-1.1737 0.10717-0.53611 0.62502-0.88678 1.1626-0.78728 0.291 0.058 7.118 1.451 11.331 4.874 0.031 0.021 0.062 0.043 0.091 0.067 0.88886 0.70673 1.649 1.5616 2.247 2.527 1.628 2.715 0.727 4.622-0.66 5.5-0.79795 0.47012-1.7111 0.7087-2.637 0.689z"/>
|
||||
<path d="m7.967 32.539c-2.577 0-4.707-0.525-5.767-1.939-0.33137-0.44183-0.24183-1.0686 0.2-1.4s1.0686-0.24183 1.4 0.2c1.28 1.7 6.723 1.5 14.207-0.545 0.53296-0.14525 1.0827 0.16904 1.228 0.702s-0.16904 1.0827-0.702 1.228c-3.4356 1.0209-6.9849 1.6101-10.566 1.754z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/img/me.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
public/img/onyx-logo-white-background.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/img/onyx-logo.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
public/img/posts/2020-08-07-hello-world/bot-a-users-graph.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/img/posts/2020-08-07-hello-world/bot-b-reviews.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
public/img/posts/2020-08-07-hello-world/iceberg.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 390 KiB |
|
After Width: | Height: | Size: 362 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 190 KiB |
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1280.000000pt" height="646.000000pt" viewBox="0 0 1280.000000 646.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.15, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,646.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M9175 6445 c-124 -20 -247 -57 -402 -121 -143 -58 -153 -61 -153 -41
|
||||
0 23 -32 44 -89 61 -91 27 -84 33 -168 -141 -180 -377 -1212 -2595 -1763
|
||||
-3790 -113 -244 -207 -443 -210 -443 -3 0 -133 278 -289 618 -654 1419 -1731
|
||||
3732 -1747 3750 -5 7 -119 -20 -146 -34 -16 -8 -28 -21 -28 -30 0 -30 -30 -24
|
||||
-163 30 -527 216 -985 167 -1371 -148 -107 -88 -340 -322 -598 -601 -443 -479
|
||||
-684 -666 -973 -752 -80 -24 -107 -27 -250 -27 -133 -1 -178 3 -265 22 -121
|
||||
28 -272 80 -418 146 -87 39 -142 56 -142 42 0 -17 367 -827 888 -1961 93 -203
|
||||
249 -543 347 -755 97 -212 182 -395 190 -406 17 -26 293 -164 385 -193 112
|
||||
-35 179 -43 405 -48 256 -6 309 2 463 68 269 115 429 249 877 739 321 351 499
|
||||
518 683 644 208 141 376 196 604 196 226 0 441 -56 688 -178 l135 -67 303
|
||||
-659 304 -660 -25 -55 c-13 -31 -129 -283 -257 -561 -350 -760 -462 -1012
|
||||
-453 -1021 16 -16 166 -48 183 -39 20 11 41 54 385 802 154 334 282 607 285
|
||||
608 3 0 151 -316 329 -703 178 -386 332 -711 342 -721 18 -19 19 -19 95 0 42
|
||||
10 83 23 91 29 16 12 -12 77 -392 905 -125 272 -254 554 -286 625 l-60 130
|
||||
308 670 308 670 131 66 c247 124 470 182 699 182 169 0 286 -27 429 -97 246
|
||||
-120 448 -298 886 -776 410 -447 582 -591 843 -704 160 -69 166 -70 422 -70
|
||||
340 0 431 20 689 152 l149 77 294 640 c462 1007 543 1184 740 1615 195 427
|
||||
393 868 393 876 0 15 -57 -3 -164 -50 -521 -230 -881 -219 -1269 42 -156 105
|
||||
-322 262 -682 647 -266 286 -443 461 -550 547 -141 113 -319 199 -492 239
|
||||
-119 27 -346 34 -468 14z m278 -11 c11 -11 -40 -137 -203 -500 l-55 -121 -125
|
||||
-6 c-206 -11 -466 -75 -622 -153 -61 -31 -98 -42 -98 -29 0 10 124 283 171
|
||||
378 105 209 155 251 404 335 158 52 507 116 528 96z m-5813 -60 c158 -32 292
|
||||
-75 396 -125 102 -48 154 -104 222 -237 54 -104 182 -389 182 -403 0 -17 -31
|
||||
-9 -98 25 -79 39 -187 76 -332 112 -79 19 -141 27 -253 31 -91 4 -150 10 -155
|
||||
17 -21 34 -239 530 -257 585 -4 14 -3 26 4 30 16 11 150 -6 291 -35z m6729
|
||||
-461 c223 -223 281 -292 281 -332 0 -15 -17 -70 -39 -122 -45 -110 -187 -415
|
||||
-207 -444 -13 -18 -28 -5 -251 222 -239 242 -286 284 -303 267 -8 -8 -241
|
||||
-500 -261 -552 -5 -12 -15 -25 -23 -28 -9 -3 -56 19 -106 51 -171 105 -282
|
||||
153 -460 198 -54 13 -55 14 -53 48 2 43 59 179 168 404 l85 175 49 0 c97 0
|
||||
289 -76 484 -192 65 -38 120 -68 122 -66 2 2 36 72 75 156 147 318 199 412
|
||||
227 412 8 0 104 -89 212 -197z m-7652 72 c29 -55 92 -184 139 -287 l87 -187
|
||||
26 18 c169 119 475 251 582 251 33 0 40 -5 62 -43 40 -68 192 -395 221 -476
|
||||
27 -76 28 -101 2 -101 -8 0 -68 -16 -133 -36 -128 -38 -220 -81 -362 -169 -50
|
||||
-31 -98 -55 -106 -53 -9 2 -72 125 -149 292 -74 158 -137 291 -140 293 -13 13
|
||||
-76 -44 -297 -268 -129 -131 -238 -239 -243 -239 -9 0 -147 285 -210 433 -58
|
||||
136 -58 159 -5 229 73 94 437 450 456 446 11 -2 39 -43 70 -103z m6133 -791
|
||||
c30 -6 32 -9 27 -40 -3 -18 -54 -138 -112 -266 -59 -128 -115 -250 -124 -270
|
||||
-15 -35 -19 -37 -76 -43 -310 -31 -416 -56 -658 -154 -71 -29 -130 -51 -132
|
||||
-49 -4 4 82 198 191 433 l79 170 55 27 c173 85 445 167 615 186 44 5 85 10 91
|
||||
11 6 0 26 -2 44 -5z m-4720 -35 c162 -25 348 -82 512 -155 l105 -47 88 -191
|
||||
c122 -263 185 -409 180 -414 -2 -3 -60 18 -128 46 -221 91 -342 122 -576 146
|
||||
-73 8 -137 18 -141 23 -9 10 -155 326 -217 471 -24 57 -42 110 -39 118 7 17
|
||||
119 19 216 3z m7250 -228 c149 -91 196 -111 368 -154 75 -18 121 -35 118 -41
|
||||
-3 -6 -56 -123 -119 -261 -134 -292 -145 -323 -126 -337 17 -11 151 -2 269 18
|
||||
117 20 235 55 386 114 136 53 154 58 154 37 0 -50 -228 -508 -289 -581 -24
|
||||
-29 -186 -102 -314 -140 -217 -66 -458 -99 -489 -68 -17 17 7 86 114 326 111
|
||||
251 124 286 107 297 -8 5 -26 9 -41 9 -71 0 -303 95 -448 182 -41 25 -89 53
|
||||
-107 62 -31 16 -33 15 -47 -6 -8 -13 -55 -111 -104 -218 -49 -107 -108 -232
|
||||
-131 -278 l-42 -83 -29 21 c-16 11 -131 126 -256 255 -125 129 -233 236 -241
|
||||
239 -11 4 -40 -48 -110 -192 -159 -330 -175 -362 -185 -369 -6 -3 -126 112
|
||||
-268 256 -141 143 -260 261 -266 261 -5 0 -33 -55 -63 -123 -75 -167 -219
|
||||
-478 -225 -485 -3 -2 -51 24 -107 58 -168 103 -374 190 -451 190 -19 0 -43 6
|
||||
-53 14 -17 12 -18 18 -7 64 6 28 52 140 103 249 50 109 103 224 118 256 l26
|
||||
59 48 -6 c140 -19 324 -91 475 -187 61 -38 115 -69 122 -69 10 0 100 180 238
|
||||
477 26 56 52 102 58 103 23 1 159 -122 340 -308 l191 -195 26 39 c14 21 78
|
||||
150 143 287 65 136 123 247 130 247 7 0 97 -88 201 -196 165 -172 315 -314
|
||||
332 -314 5 0 58 110 241 503 37 78 43 86 60 77 11 -6 78 -46 150 -89z m-9654
|
||||
-220 c74 -156 136 -286 139 -289 11 -11 94 65 307 282 151 154 230 228 237
|
||||
221 5 -5 59 -113 120 -240 127 -264 159 -325 170 -325 5 0 84 80 177 177 152
|
||||
158 331 323 353 323 4 0 68 -127 142 -282 74 -154 141 -286 150 -291 13 -8 37
|
||||
3 112 50 112 72 158 97 245 130 68 25 245 73 273 73 12 0 45 -60 109 -197 125
|
||||
-265 160 -351 160 -395 0 -40 -2 -42 -85 -53 -96 -13 -262 -86 -426 -186 -53
|
||||
-32 -99 -59 -102 -59 -10 0 -62 107 -177 365 -57 127 -107 234 -112 240 -5 6
|
||||
-111 -95 -272 -259 l-263 -268 -24 43 c-13 24 -76 151 -139 283 -63 131 -121
|
||||
241 -128 244 -8 3 -111 -94 -265 -252 -139 -141 -257 -256 -263 -256 -6 0 -25
|
||||
30 -42 68 -40 88 -219 470 -234 500 -6 12 -19 22 -28 22 -9 0 -55 -23 -101
|
||||
-52 -154 -94 -399 -198 -467 -198 -16 0 -36 -6 -46 -13 -16 -12 -16 -16 7 -77
|
||||
14 -36 48 -117 77 -180 62 -138 126 -295 135 -332 10 -40 -21 -52 -113 -44
|
||||
-257 24 -630 146 -699 230 -55 67 -265 485 -279 556 -4 19 -2 30 5 30 6 0 68
|
||||
-22 138 -50 71 -27 157 -58 193 -69 193 -59 463 -91 476 -57 6 16 -40 128
|
||||
-168 405 -49 106 -87 195 -86 196 2 1 62 16 133 34 147 37 243 79 395 174 58
|
||||
36 111 65 119 64 7 -1 74 -130 147 -286z m6590 -783 c4 -4 -54 -139 -128 -300
|
||||
l-136 -293 -143 -6 c-236 -10 -372 -44 -651 -163 -34 -14 -38 -14 -38 -1 0 21
|
||||
129 307 203 450 l62 120 75 37 c134 66 331 128 485 153 91 14 257 16 271 3z
|
||||
m-3506 -38 c118 -22 308 -84 414 -135 61 -29 82 -45 103 -78 48 -76 259 -535
|
||||
250 -544 -3 -2 -60 19 -128 46 -227 91 -410 131 -606 131 l-100 0 -132 286
|
||||
c-72 157 -132 290 -134 296 -6 32 163 31 333 -2z m5941 -161 c164 -99 318
|
||||
-168 438 -195 92 -21 101 -24 101 -35 0 -6 -56 -135 -125 -286 -69 -152 -128
|
||||
-287 -132 -301 l-6 -25 124 6 c206 11 338 44 598 151 62 26 115 45 118 43 2
|
||||
-3 -44 -110 -103 -238 -58 -129 -120 -264 -136 -301 l-30 -66 -121 -52 c-170
|
||||
-72 -337 -128 -434 -145 -107 -19 -298 -31 -305 -19 -3 5 46 122 109 259 148
|
||||
324 157 346 142 356 -7 4 -69 24 -138 44 -158 47 -227 78 -369 167 -97 61
|
||||
-115 69 -127 57 -8 -8 -66 -122 -129 -255 -120 -251 -153 -314 -165 -314 -29
|
||||
0 -179 142 -389 368 l-143 153 -41 -88 c-119 -259 -229 -473 -241 -473 -8 0
|
||||
-84 73 -170 163 -85 89 -202 204 -259 256 l-105 93 131 289 c97 213 135 289
|
||||
148 289 29 0 135 -95 340 -304 108 -110 199 -199 201 -196 9 9 84 166 182 378
|
||||
54 117 102 211 107 210 4 -2 97 -97 205 -212 180 -191 312 -316 331 -316 4 0
|
||||
36 67 71 148 128 290 203 442 221 442 9 0 55 -23 101 -51z m-8543 -66 c27 -54
|
||||
88 -187 137 -295 49 -109 92 -198 97 -198 20 0 161 136 338 324 106 114 197
|
||||
203 201 199 4 -5 61 -123 127 -263 65 -140 127 -272 138 -293 l18 -38 211 215
|
||||
c211 215 306 299 332 294 7 -2 72 -132 144 -290 l130 -286 -53 -48 c-29 -26
|
||||
-146 -141 -260 -257 -142 -143 -212 -208 -222 -204 -17 7 -81 130 -193 372
|
||||
-41 88 -78 164 -83 169 -6 6 -44 -28 -97 -85 -161 -174 -368 -380 -401 -401
|
||||
-29 -18 -36 -19 -47 -7 -15 15 -52 88 -191 377 -51 105 -96 192 -100 192 -3 0
|
||||
-54 -30 -113 -67 -138 -87 -217 -122 -380 -172 -73 -22 -136 -42 -138 -45 -7
|
||||
-7 3 -33 123 -296 116 -257 134 -298 134 -313 0 -14 -213 -2 -318 18 -100 19
|
||||
-268 76 -421 143 -89 39 -118 57 -129 79 -38 71 -262 568 -260 575 2 4 53 -13
|
||||
113 -38 168 -69 296 -111 387 -129 106 -21 338 -32 338 -17 0 6 -56 134 -124
|
||||
285 -69 150 -128 285 -131 299 -6 25 -4 26 67 43 151 37 300 102 467 204 46
|
||||
28 90 51 98 51 7 0 35 -44 61 -97z m7959 -1174 c159 -103 360 -190 473 -205
|
||||
80 -11 80 -8 20 -151 -82 -198 -178 -395 -207 -425 -14 -15 -38 -30 -52 -33
|
||||
-35 -7 -177 34 -283 83 -66 31 -309 170 -327 188 -5 4 271 604 278 604 2 0 46
|
||||
-27 98 -61z m-7293 -268 c75 -162 135 -296 133 -297 -11 -11 -237 -143 -290
|
||||
-171 -78 -39 -263 -103 -298 -103 -48 0 -84 35 -132 126 -54 106 -197 438
|
||||
-197 458 0 16 14 21 84 31 106 15 299 100 460 205 50 32 94 56 98 52 3 -4 67
|
||||
-139 142 -301z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 143 KiB |
BIN
public/img/posts/2020-08-27-sponsoring-onyx/i-need-healing.jpg
Normal file
|
After Width: | Height: | Size: 892 KiB |
BIN
public/img/posts/2020-08-27-sponsoring-onyx/some-notebooks-1.png
Normal file
|
After Width: | Height: | Size: 774 KiB |
BIN
public/img/posts/2020-08-27-sponsoring-onyx/some-notebooks-2.png
Normal file
|
After Width: | Height: | Size: 926 KiB |
|
After Width: | Height: | Size: 51 KiB |
BIN
public/img/posts/2020-08-27-sponsoring-onyx/thinking-meme.jpg
Normal file
|
After Width: | Height: | Size: 254 KiB |
11
public/styles/common.css
Normal file
@@ -0,0 +1,11 @@
|
||||
@import './header.css';
|
||||
@import './footer.css';
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
scroll-behavior: smooth;
|
||||
font-size: 1.2em;
|
||||
font-family: 'Vollkorn', serif;
|
||||
width: 100%;
|
||||
}
|
||||
11
public/styles/footer.css
Normal file
@@ -0,0 +1,11 @@
|
||||
footer {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
text-align: center;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
footer {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
41
public/styles/header.css
Normal file
@@ -0,0 +1,41 @@
|
||||
header {
|
||||
width: calc(100% - 2rem);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
padding: 4rem 1rem;
|
||||
}
|
||||
|
||||
header .me {
|
||||
display: block;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
header .me img {
|
||||
height: 14rem;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
header .text {
|
||||
max-width: 30rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
/* header .tablet-hide {
|
||||
display: none;
|
||||
} */
|
||||
|
||||
header {
|
||||
padding-top: 0rem;
|
||||
padding-bottom: 0rem;
|
||||
}
|
||||
|
||||
header .me {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header .text {
|
||||
max-width: 25rem;
|
||||
}
|
||||
}
|
||||
43
public/styles/index.css
Normal file
@@ -0,0 +1,43 @@
|
||||
@import './common.css';
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.posts {
|
||||
/* list-style: none; */
|
||||
margin-top: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.posts li {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
column-gap: 0.5rem;
|
||||
}
|
||||
|
||||
.posts .date {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
main {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.posts {
|
||||
padding-left: 2rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.posts .date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.posts li {
|
||||
display: list-item;
|
||||
}
|
||||
}
|
||||
171
public/styles/post.css
Normal file
@@ -0,0 +1,171 @@
|
||||
@import './common.css';
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
main > h1 {
|
||||
font-size: 3rem;
|
||||
line-height: 3rem;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
max-width: 50rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
main > h1 {
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
main > .meta {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
main > h1, main > .meta {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
main > hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
background-color: lightgray;
|
||||
width: 3rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
article {
|
||||
max-width: 35rem;
|
||||
}
|
||||
|
||||
article .secret-link {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
/* article .external-link:not(.secret-link)::after {
|
||||
content: " " url('/public/icon/external-link.svg');
|
||||
zoom: .6;
|
||||
} */
|
||||
|
||||
main > h1,
|
||||
main > .meta,
|
||||
article > p,
|
||||
article > h2,
|
||||
article > h3,
|
||||
article > h4,
|
||||
article > h5,
|
||||
article > h6
|
||||
{
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.off {
|
||||
padding: 1px 1rem;
|
||||
background-color: rgba(0, 0, 0, 0.025);
|
||||
border: 1px solid lightgray;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.hero {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero big {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
width: calc(100% - 2rem - 2rem);
|
||||
border-left: 5px solid lightgray;
|
||||
padding: 1px 0;
|
||||
padding-left: calc(2rem - 5px);
|
||||
padding-right: 2rem;
|
||||
margin-left: 0rem;
|
||||
background-color: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
|
||||
pre[class*="language-"] {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
/* padding: 0 0.25rem; */
|
||||
}
|
||||
|
||||
details {
|
||||
max-width: 100vw;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
details[open] .spoiler-content {
|
||||
box-sizing: border-box;
|
||||
padding: 1px 1rem;
|
||||
background-color: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
|
||||
summary {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
article hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
background-color: lightgray;
|
||||
width: 3rem;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
nav.table-of-contents ol {
|
||||
/* Would still begin from 1 on Chrome =( */
|
||||
/* counter-reset: list-item 0; */
|
||||
|
||||
counter-reset: list-item -1;
|
||||
counter-increment: list-item 1;
|
||||
}
|
||||
|
||||
nav.table-of-contents ol li {
|
||||
display: block;
|
||||
counter-increment: list-item 1;
|
||||
}
|
||||
|
||||
nav.table-of-contents ol li:before {
|
||||
content: counters(list-item, '.') '. ';
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
html, body {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling:touch;
|
||||
margin: 0;
|
||||
font-family: 'Ubuntu', sans-serif;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3em;
|
||||
color: #e9573f;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 4em;
|
||||
background-color: #e9573f;
|
||||
}
|
||||
|
||||
.footer .email-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer a:link, .footer a:visited, .footer a:active, .footer a:focus {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.footer .social-icon {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.footer .social-icon:not(:first-child) {
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
|
||||
.footer .social-icon img {
|
||||
height: 2.2em;
|
||||
margin-bottom: -0.2em;
|
||||
}
|
||||
|
||||
@media (min-width: 767px) {
|
||||
.title {
|
||||
font-size: 5em;
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
.footer .email-link {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.footer .social-icons {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.footer .social-icons .email-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||