Oracle: nvl is not lazy

We all use nvl. It’s so common and easy(3 chars among 8 in coalesce and 6 in decode) to write it in queries, but there is one thing you should keep in mind when using NVL.

First, let’s face the problem:

create package test_pck is

    function get_user_id return number;
end;
/

create or replace package body test_pck is

    function get_user_id return number
    is
        l_res number;
    begin
        <<lbl>>
        if 1 < 2 then
            goto lbl;
        end if;    end;
end;
/

Here we have created a package with a function that never returns a value, because it contains an infinity loop.

I picked this method for demonstration to be sure that examples will show you the same result despite IDE and environment settings you have.

So, let’s run this query:

select nvl(1, test_pck.get_user_id)
from dual

It has hung.

It tells us that the test_pck.get_user_id function was called despite the fact that the first parameter is 1, which is not null.

Generally, it’s not a problem. But it may be, if your second argument in nvl is a heavy function. In this case SQL query might work slower than you expect.

Do all functions that work with null values work the same? Let’s see:

COALESCE:

-- Lazy
select coalesce(1, test_pck.get_user_id)
from dual

DECODE:

-- Lazy
select decode(1, 1, 1, test_pck.get_user_id)
from dual

CASE:

-- Lazy
select case
           when 1 = 1 then 1
           else test_pck.get_user_id
       end
from dual

We forgot about nvl’s brother - NVL2

-- Not Lazy
select nvl2(1, 2, test_pck.get_user_id)
from dual

Yes, it’s not lazy, like nvl.

What to choose

nvl meme

I think it’s not a problem when you use nvl with “static” values. But if you use functions as one (or both) arguments to nvl, it’s better to replace it with a call to something lazier.

nvl meme

Using Typescript to force errors handling

Summary: Typescript’s discriminated unions may be used to force you to handle exceptions.

The problem

If a function can throw an error, it should be wrapped in try/catch block to be properly handled.

However, error handling can be ignored, which adds more room for potential errors.

function getUserFromStorage(id: string) {
  return undefined
}

function getUser(id: string) {
  const user = getUserFromStorage(id)
  if (user === undefined)
    throw new Error('Specified user does not exist')

  return user
}

function printUserInfo(id: string) {
  const user = getUser(id)

  console.log(`User name is ${user.name}`)
}

The problem here is that we didn’t check for errors when we retrieve user from our storage. Moreover, TS compiler don’t actually care.

Ideally, printUserInfo should handle possible errors:

function printUserInfo(id: string) {
  try {
    const user = getUser(id)

    console.log(`User name is ${user.name}`)
  }
  catch {
    console.error('Some error')
  }
}

Discriminated unions

A union type is a type that combines multiple types into one. A variable of a union type can store only values with those types:

type mode = 'edit' | 'view' | number

// ok, type ='edit'
const a = 'edit'

// ok, type = number
const b = 24

// ok, type = 'view'
const c = 'view'

// type error: type string is unassignable to type mode
const d = 'randomstring'

Union types and type narrowing

When dealing with union types, we often need to narrow them before use:

type StringOrNumber = string | number

function getStringOrNumber(): StringOrNumber {
    return 2
}

let v = getStringOrNumber()

// Error!
// The left-hand side of an arithmetic operation must be of 
// type 'any', 'number', 'bigint' or an enum type.
console.log(v ** 3)

See, typescript complains because it doesn’t know whether v is string or number, Therefore, we need to make sure that v is a number:

type StringOrNumber = string | number

function getStringOrNumber(): StringOrNumber {
    return 2
}
let v = getStringOrNumber()

if (typeof v === 'number')
    console.log(v ** 3)
else
    console.log(v.toLowerCase())

Take a look at the last example one more time; did you notice console.log(v.toLowerCase())?

It works because this statement is placed in the else branch of our check, so typescript knows that v is a string.

Fixing the problem

We can use union types and required type narrowing to make result checking mandatory - or our program won’t be compiled.

This is how it can be implemenented.

First of all, we create two main types and their union:

interface OkResult<T> {
  ok: true
  value: T
}

interface FailResult {
  ok: false
  error: string
}

type OkOrFail<T> = OkResult<T> | FailResult

Each of these types has ok field, which we can use to narrow OkOrFail type to OkResult or FailResult:

type User = {
    name: string
    email: string
}

function getUser(id: number): OkOrFail<User> {
  try {
    const user = getUserFromDb(id)

    return {
      ok: true,
      value: user,
    }
  }
  catch {
    return {
      ok: false,
      error: 'can\'t find a user'
    }
  }
}

We used try/catch to return OkResult or FailResult, so our function doesn’t throw errors.

It returns union type instead, and in order to work with the returned error we need to narrow result to OkResult type:

const u = getUser(1)

// Type Error!
// If u is `FailResult`, it doesn't have the `value` field!
console.log(u.value)

// Now everything is ok, we narrow result down to `OkResult` type
if (u.ok)
  console.log(u.value)

Always returning literal objects is too much to type, so we can create helper functions for this:

function ok<T>(value: T): OkResult<T> {
  return {
    ok: true,
    value,
  }
}

function fail(error: string): FailResult {
  return {
    ok: false,
    error,
  }
}

And then our getUser can be refactored:

function getUser(id: number): OkOrFail<User> {
  try {
    const user = getUserFromDb(id)

    return ok(user)
  }
  catch {
    return fail('can\'t find a user')
  }
}

That’s it, I hope you liked this article, good luck!

Create signals in plain JS

In this article, we’ll implement our own signals.

What are signals

Signals are objects that incapsulate access to their original value and track dependencies that use these signals.

Yes but why?

The goal of this post is to have fun and to create the basic understanding through practice of how such things can work.

Real world signals examples

Vue

In vue3, there are two main reactivity primitives: ref and reactive. They’re not called signals in vue, but they’re the same. From the documentation:

Fundamentally, signals are the same kind of reactivity primitive as Vue refs. It’s a value container that provides dependency tracking on access, and side-effect triggering on mutation.

Vue automatically tracks dependencies that use refs or reactive objects, and triggers re-render or re-computation (if we talk about such thing as computed) when their value is changed.

Additionally, vue provides ‘watchers’(watchwatchEffect), which run callback functions any time their ‘watched’ value has been changed. In code it looks this way:

const name = ref('name')

watch(name, (newName) => {
  console.log(newName)
})

S.js

In S.js, signals are created with the S.data function. To change the signal’s value, you call signal as a function with an argument, and you call signal without arguments to get its current value:

const name = S.data('Andrew')
name('Saphir')
console.log(name()) // prints 'Saphir'

S.js has the on method, which is identical to vue’s watch:

const counter = S.data(0)

S.on(counter, () => {
  console.log('The counter has been changed')
})

Design signals

Our signals will work as in the S.js library - createSignal() function will return a function that can be used as a setter when we provide a new value, and as a getter when called without arguments:

const userName = createSignal('User13')

console.log(userName()) // prints 'User13'

userName('User')
console.log(userName()) // prints 'User'

Update value with function

For simple values like strings or numbers changing values by simply passing them as arguments is ok, but for more complex types it may be too verbose. Imagine a user object with a complex structure like this:

const user = {
  name: 'User13',
  age: 44,
  email: 'user13@mail.com',
  created_at: '2024-01-01',
}

To update one property, we have to pass a new value to a signal:

const signal = createSignal(user)

signal({
  name: 'User02',
  age: 44,
  email: 'user13@mail.com',
  created_at: '2024-01-01',
})

console.log(signal().name) // 'User02'

We can, hovever, simplify this by using spread operator and signal as a getter:

const signal = createSignal(user)

signal({
  ...signal(), // Will return the current object
  name: 'User02',
})

Looks better, yet we can make it better - pass a callback function with one parameter - current signal’s value, and assign result as a new value:

const signal = createSignal(user)

signal(u => ({
  ...u,
  name: 'User02',
}))

Or with simple types:

const signal = createSignal(3)

signal(v => ++v)

console.log(signal()) // prints '4'

Track signal changes

Signals as containers for values are not very useful, though. We want to be able to perform some actions when signal’s value changed. For this, we’ll create a function named on:

const s = createSignal(12)

on(s, (newVal) => {
  console.log(`New value is ${newVal}`)
})

s(13)
s(v => v++)

What we expect from this code? It should print these two lines:

New value is 13
New value is 14

Implementation

First thing that we’ll create is a function that acts differently depending whether it’s called with arguments or without them. For this, we need the arguments object.

function signal(param) {
  if (arguments.length === 0)
    console.log('Without arguments')
  else
    console.log('With arguments')
}

signal() // 'Without arguments'
signal(23) // 'With arguments'

Note that we can’t check param for undefined, because in this case we won’t be able to distinct signal() and signal(undefined) calls:

function signal(param) {
  if (param === undefined)
    console.log('Without arguments')
  else
    console.log('With arguments')
}

signal() // 'Without arguments'
signal(2) // 'With arguments'

// Oh no! It prints 'Without arguments'!
signal(undefined) // 'Without arguments'

createSignal

For keeping the same state between signal function calls we’ll wrap our state variable in a closure.

function createSignal(value) {
  let _value = value

  function signal(v) {
    const isSetter = arguments.length > 0

    if (isSetter) {
      if (typeof v === 'function') {
        _value = v(_value)
      } else {
        _value = v
      }
    } else {
      return _value
    }
  }

  return signal
}

const name = createSignal('Anna')
console.log(name()) // 'Anna'
console.log(name('Tanya'))
console.log(name()) // 'Tanya'

And that’s it, our signal is ready. It’s simple, but it works! And it also works with functions, as we planned:

const user = createSignal({ name: 'Anna', age: 41 })
user(u => ({...u, name: 'Tanya'}))
console.log(user().name) // 'Tanya'
console.log(user().age) // 41

on function

This function takes a signal and a callback that should be executed when the signal is changed. At this point, we should think about few things:

  1. We need some data structure to store callbacks
  2. We need to modify the signals’ implementation and execute required callbacks when a signal is executed as a “setter”.

Data structures go first. We’ll use Map with signals as its keys and array of callbacks as its values. It will allow us to quiclky find required callbacks. This map should be global for the whole module:

const effects = new Map()
function on(signal, cb) {
  const signalEffects = effects.get(signal)

  if (signalEffects) {
    signalEffects.push(cb)
  } else {
    effects.set(signal, [cb])
  }
}

Very simple, isn’t it? We just push the callback to the array of already existed callbacks if it exists. If not, we create a brand new array with just one value - our callback.

Finally, we need to find these callbacks and execute them in our signals. This is the code that implements it:

// Find registered callbacks
const signalEffects = effects.get(signal)
if (signalEffects) {
  for (const cb of signalEffects) {
    cb(newSignalValue)
  }
}

What’s next?

I plan to write one more post which will introduce a few improvements to our current signals, so stay tuned in!

Full source

const effects = new Map()

function ss(value) {
  let _value = value

  function signal(v) {
    const isSetter = arguments.length > 0

    if (isSetter) {
      if (typeof v === 'function') {
        _value = v(_value)
      } else {
        _value = v
      }

      // Find registered callbacks
      const signalEffects = effects.get(signal)
      if (signalEffects) {
        for (const cb of signalEffects) {
          cb(_value)
        }
      }
    } else {
      return _value
    }
  }

  return signal
}

function on(signal, cb) {
  const signalEffects = effects.get(signal)

  if (signalEffects) {
    signalEffects.push(cb)
  } else {
    effects.set(signal, [cb])
  }
}

Let’s do something with our signals

For demonstration purposes, let’s create a simple web page with a button and a counter for the number of times the button was clicked.

<html>
	<head>
		<script type="text/javascript" src="index.js"></script>
		<script type="text/javascript">
			const counter = createSignal(0)

			function onClick() {
				counter(v => ++v)
			}

			window.addEventListener('load', () => {
				const btn = document.querySelector('button')
				// Display initial counter's value in the button
				btn.innerText = counter()

				// On each click, increment counter value
				btn.addEventListener('click', onClick)

				// Every time when the counter was changed,
				// update button text with the new value
				on(counter, (newValue) => {
					btn.innerText = newValue
				})
			})
		</script>
	</head>
	<body>
		<button> </button>
	</body>
</html>

Links

Setup volar v2+ in neovim

Suppose you have Neovim and kickstart installed, you program in vue and typescript, and you want to have all these fancy features that volar offers.

In the ideal world, simply adding volar={} in LSP config should be enough, but starting from volar v 2.0 and higher, typescript support was moved to a separate package - @vue/typescript-plugin.

First of all, we need to install it globally:

npm i -g @vue/typescript-plugin

Then, open the init.lua file, find the code with local servers = {..} and make sure your tsserver config looks like this (add this section if it doesn’t exist):

tsserver = {
  init_options = {
      plugins = {
        {
          name = "@vue/typescript-plugin",
          -- Exact location of the typescript plugin
          location = "/usr/local/lib/node_modules/@vue/typescript-plugin",
          languages = {"javascript", "typescript", "vue"},
        },
      },
  },
  -- Add TS support for vue files
  filetypes = {'vue', 'javascript', 'typescript'}
}

You need to set the location of where the @vue/typescript-plugin is installed. To find out where is it, run this command:

npm root -g

This command prints the path to the directory where global packages are installed (on linux and mac, it’s usually /usr/local/lib/node_modules).

The last step - add the volar server:

local servers = {
  tsserver = {...},
  volar={}
  -- You can also add additional useful
  -- LSP servers, for example:
  -- eslint = {}
  -- tailwindcss = {}
}

That’s it, after restarting neovim, you’ll have the full experience of volar!

LOL: Workflowy privacy policy

I’ve been an almost happy workflowy’s user for about a year, and as I wrote earlier , I’m done with workflowy. Yesterday, I read their privacy policy more carefully, and, you know, it’s full of gems, check it out:

Under the 2. Data that we use, receive, collect, process, share or store and how we may use it, they have a few nice points:

2.1.2. We might use, receive, collect, process or store Personal Data on potential customers, customers, employees, service providers, users of the Services and the Website, etc.

2.1.3.8. AS MOST OF THE DATA IS PROVIDED BY THE USER OF THE SERVICES WITHOUT OUR KNOWLEDGE, PROVIDE OTHER CATEGORIES OF PERSONAL DATA, SPECIFICALLY “SENSITIVE” AND “SPECIAL CATEGORIES OF DATA” (AS DEFINED BY GDPR i.e. medical data, financial data, political opinions, religious data, childrens’ data etc ) IS UNDER THE USER’S SOLE RESPONSIBILITY AND OWN RISK AND WE RECOMMEND NOT PROVIDING THIS TYPE OF DATA.

LOL, What kind of data I supposed to keep safe in Workflowy then?

And another one:

2.1.4.3. Internal business: We may use your Personal Data for internal business purposes, including, without limitation, to help us improve our Services, Website content and functionality, to better understand our customers and users, to protect against, identify or address wrongdoing, to enforce our contracts and this Privacy Policy, to provide you with customer service and to generally manage and operate our business (e.g., pay salaries and make considerations).

WTF is “Internal business purposes”, huh?

And this is for all users - even for those who have paid money. Oh my god, they suck so hard.

I know that almost all online web services have similar privacy policies, I just wrote about one of them.


Problem solved: Hugo did not update content on linux

Recently I was faced with a weird hugo behaviour on linux - it didn’t update the content of the site after running the dev server.

First thing that I tried is to run hugo with disabled “Fast Render Mode”:

hugo server --disableFastRender

And it didn’t help.

Solution: Reboot linux. I can’t find the link right now, but I found this answer somewhere on the internet. Turned out, it’s all because of suspend in linux - somehow the fact that I wasn’t shutting down a system relates to this issue.

Asciidoctor HTML output mess

Asciidoctor is a markup language, similar to markdown. One of its tools, asciidoctor-js (and most probably asciidoctor version written in Ruby), wraps every block (paragraphs, lists and so on) in a div. Resulting HTML is a mess.

For example, simple code listing is wrapped in three divs:

<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-vue" data-lang="vue">&lt;script setup lang='ts'&gt;
import { useFocus } from '@vueuse/core'
&lt;/script&gt;</code></pre>
</div>
</div>
</div>

Asciidoctor tutorial

Asciidoctor is a markup language similar to markdown, but more readable.

Installation

Asciidoctor has multiple “backends”, so you can choose from multiple options:

Node

Run

npm i -g asciidoctor

Ruby

Search for a package with name asciidoctor:

apt-get install asciidoctor

How to convert asciidoctor page to html

asciidoctor page.adoc -o page.html

The best feature of Asciidoctor #1

Links are easy to remember, check it out:

This link is parsed automatically:

https://example.com

This link will render as a word 'link':

https://example.com[link]

If you want to open a link in a new tab:

https://example.com[window=_blank]

https://example.com[link^]

Mailto links are also automatically parsed:

mailto:username@example.com

mailto:username@example.com[email me]

The best feature of Asciidoctor #2

Images.

Now you’ll never being thinking whether you wrote a link or an image element.

image::coolpic.png[]

image::coolpic.png[cool picture]

Basic elements

This example should give you the full understanding of the base elements in asciidoctor:

= Asciidoctor tutorial

Asciidoctor is a powerfull and elegand
markup language, much better than markdown.

It's strengths:

- Links
- Images
- Elegant headings syntax


== Text formatting

- **Bold text**
- __Italic text__
- +++Underlined text+++


== Blockquotes

Blockquotes are also better than in markdown:

----
This is a blockquote
----

Authoring is also supported:

[quote, proj11.com]
----
Asciidoctor as a **markup** language is better
than markdown, but its backends suck.
----

Links


Emacs: How to add bookmarks to files and directories

Very useful feature of Emacs: You can bookmark directories and files and switch between them quickly.

To add the current dired directory to bookmarks, press M-x r m in dired, then type bookmark name.

To add bookmark to a file, use the same keystroke in a window with a file.

To jump to a bookmark press M-x r l, move to required bookmark in the list and hit enter