Skip to content

Instantly share code, notes, and snippets.

@rgchris
Last active July 20, 2022 13:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rgchris/c2e51153ed4b2b2b44fa03ce1d381ab9 to your computer and use it in GitHub Desktop.
Save rgchris/c2e51153ed4b2b2b44fa03ce1d381ab9 to your computer and use it in GitHub Desktop.
Custom Types
// The journey to creating a new object type begins with ... a function
// * It doesn't have to be a named function (that is `function name()`
// as opposed to `name = function ()`) but there are advantages to this
// that are beyond the scope of this comment.
// * As a value, `myNumType` here serves double-duty--as a function in
// the sense of a passable first-class value, as, say, in Rebol
// * --and as a constructor for objects that use `myNumType` as a
// prototype
// * The value of `this` depends on the context in which the function
// `myNumType` is called. If you call it by itself, `this` refers to the
// global context (`window` or whatever `globalThis` refers to)
// * When called with `new`, `this` refers to a new object that is
// returned by `new` (unless you explicitly return something else)
// and whose 'default' values refer to `myNumType.prototype` and any
// other objects up the prototype chain all the way back to
// `Object.prototype` (prototype chain also beyond the scope of these
// comments)
//
function myNumType(value, unit) {
this.value = value
this.unit = unit
}
// `Object.assign` is just a fancy way to extend an object where you
// can pass the new properties as an object. I just find this a little
// cleaner than `myNumType.prototype.property = ...; ...repeat...`
//
Object.assign(
myNumType.prototype, {
// `.valueOf` is used by operators for diserning a value they
// might understand
//
valueOf: function () {
return this.value * 2
},
// `.toString` affects how a value is formed, not necessarily
// serialization, though you can add `.toJSON` these days for
// when a value is encountered by `JSON.stringify`
//
toString: function () {
return '' + this.value + this.unit
// '' + -- coerces concatenation
}
}
)
// Create a new object using `myNumType.prototype`
//
let num = new myNumType(
1, 'em'
)
// Using `Array.prototype.join` to invoke stringification.
// * `num + 2` invokes `.valueOf` and operates on that value,
// in this case a number, thus producing a number
//
console.log(
['=>', num + 2, num]
.join(' ')
)
//
// => 4 1em
// Expected output
Rebol [
Title: "Custom Type"
Author: "Christopher Ross-Gill"
Date: 20-Jul-2022
Notes: https://forum.rebol.info/t/could-strings-have-context/587/18
]
; Rebol's URL! type is the most hackable type lexically
; * strictly starting `word colon` you can follow it with
; any non-zero number of non-space characters with the caveat
; although historically Rebol has mangled percent-encoded
; sequences
; * whatever the `word` part is will connect the value to
; an associated scheme if transformed to a PORT! value
;
my-literal-value: my-special-num-type:1em
digit: charset "0123456789"
letter: charset "abcdefghijklmnopqrstuvwxyz"
; MAKE-SCHEME is just a helper, you can view the source to
; see what it does
;
sys/make-scheme [
name: 'my-special-num-type
title: "My Special Number Type"
; I *think* `state` is the best place to put this prototype
;
state: make object! [
value: none
unit: none
]
; `init` is called on the new PORT! that is created with
; `make port! spec` or some of the higher level actors
; that implicitly create a PORT!, such as `open spec`
;
init: func [
this
][
this/state: make state [
parse this/spec/ref [
"my-special-num-type:"
copy value some digit
copy unit some letter
]
]
]
; Note this is not an OBJECT!-based prototype,
; MAKE-SCHEME does this transformation to avoid
; binding issues
;
actor: [
select: func [this property] [
get in this/state property
]
copy: func [this] [
to url! rejoin [
"my-special-num-type:"
this/state/value this/state/unit
]
]
]
]
num: make port! my-literal-value
print [
"=>"
select num 'value select num 'unit
copy num
]
;
; => 1 em my-special-num-type:1em
; Expected output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment