Skip to content
Back to skills

Dum Dum Non Ts

ASecurity

Use when writing or editing source files in non-TypeScript general-purpose languages.

  • 5 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 19, 2026
developmenttypescriptpythonrustgojavarubyphpswiftkotlinc++

Works with

  • terminal
  • api

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add Aquaticat/Monochromatic --skill dum-dum-non-ts --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dum Dum Non Ts?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dum Dum Non Ts
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aquaticat-dum-dum-non-ts/badge)](https://www.skillsdirectory.com/skills/aquaticat-dum-dum-non-ts)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dum-dum-non-ts
description: Use when writing or editing source files in non-TypeScript general-purpose languages.
---

# Dum-dum non-TS

Fires when writing or editing source files in non-TypeScript general-purpose
programming languages:
 C,
 C++,
 Rust,
 Go,
 Python,
 Java,
 Kotlin,
 Swift,
 Ruby,
PHP,
 Lua,
 Zig,
 Nim,
 Haskell,
 OCaml,
 Elixir,
 Clojure,
 Scala,
 F#,
 or any other.

The skill encodes two rules (simplest possible constructs;
 comments on every
concept-introducing line) and a comment template (What,
 Why,
 optional Gotcha)
with a TypeScript pseudocode equivalent above every concept-introducing line.

See "Out of scope" at the bottom for file types this skill does not apply to.

## Audience

The human reader knows **only TypeScript**.
 Optimise comments and code shape
for them,
 not for an experienced practitioner of the target language.
 The
compiler does not read the comments;
 the user does.

## Two rules

### Rule 1 — Simplest possible constructs

Write boring,
 beginner-level code.
 Forbidden by default:

- macros,
   metaprogramming,
   reflection,
   code generation
- operator overloading,
   custom conversion operators
- template / generic gymnastics beyond a single type parameter
- point-free chains,
   monad stacks,
   `do`-notation
- decorators,
   mixins,
   multiple inheritance
- comprehensions / generators when their syntax differs from TS
- pattern matching used for control flow that an `if`/`else` chain handles
- "clever" one-liners,
   ternaries longer than `cond ? a : b`

Prefer:
 plain named functions,
 named local variables,
 explicit type
annotations where the language allows them,
 `if`/`else`,
 `for` loops,
 early
`return`s,
 one statement per line.
 **If two ways exist,
 pick the one whose
translation to TS is mechanical.
**

If the task genuinely needs a construct with no clean TS analogue (manual
memory management,
 lifetimes,
 async runtimes,
 FFI,
 channels),
 stop and ask
the user whether to (a) proceed with a verbose comment that admits the
analogy is loose,
 (b) wrap the gnarly bit in a tiny helper and only use the
helper from then on,
 or (c) pick a different language for this piece.

### Rule 2 — Comments on every concept-introducing line

A line is **concept-introducing** if it is any of:

- an import / `#include` / `use` / `require`
- a function,
   method,
   type,
   struct,
   class,
   trait,
   interface,
   or enum
  declaration
- a **wrapper or variant constructor**:
   `Some(...)`,
   `None`,
   `Ok(...)`,
  `Err(...)`,
   `Box::new(...)`,
   `Rc::new(...)`,
   `Arc::new(...)`,
  `Cell::new(...)`,
   `RefCell::new(...)`,
   `Vec::new()`,
   `String::new()`,
  Haskell's `Just x` / `Nothing`,
   Python's `Optional[X]` annotation,
   etc.
  These exist precisely because the language lacks `null` / `throw`.
   Every
  appearance is concept-introducing for a TS reader,
   **including bare
  one-token tails like `Ok(rules)` or `None`**,
   so every appearance carries a
  comment.
   How long that comment is depends on whether this is the concept's
  first appearance in the file;
   see "Full block on a concept's first
  occurrence in each file".
- a **type-conversion or wrapper-unwrap method call**:
   `.to_string()`,
  `.to_owned()`,
   `.into()`,
   `.from(...)`,
   `.clone()`,
   `.as_str()`,
  `.as_bytes()`,
   `.unwrap()`,
   `.unwrap_or(...)`,
   `.unwrap_or_else(...)`,
  `.unwrap_or_default()`,
   `.expect(...)`,
   `.ok()`,
   `.ok_or(...)`,
  `.collect()`,
   `.into_iter()`,
   the `?` propagation operator.
   (Same idea
  in other languages:
   Python's `dict.get(k, default)`,
   Go's `, ok` comma-ok
  pattern,
   Kotlin's `?:` Elvis,
   Swift's `as!` / `as?`.
  )
- a **borrow / reference / deref expression**:
   `&x`,
   `&mut x`,
   `*x`,
  Rust lifetimes `'a`,
   C/C++ pointer arithmetic,
   Go's `&v` / `*v`.
   Even
  if the line looks like a plain function call,
   **every `&` / `&mut`
  argument is concept-introducing** because it states ownership intent
  ("I am only lending this to you").
- a **closure / lambda** with non-TS-arrow syntax:
   Rust `|x| ...` /
  `|&x| ...`,
   Ruby `do |x| ... end`,
   Haskell `\x -> ...`,
   etc.
- a **`match` / pattern-match expression** used to extract from
  `Option` / `Result` / sum types (`match x { Some(v) => ..., None => ... }`,
  `match r { Ok(v) => ..., Err(e) => ... }`).
   Even one-arm `if let
  Some(v) = x` counts.
- an **implicit-return tail expression**:
   a line at the end of a function
  body whose value becomes the return because there's no trailing `;`.
  Examples:
   `Ok(rules)`,
   `Some(escape_literal(trimmed))`,
   `(line, col)`,
  `if cond { a } else { b }`.
   The reader has to know **both** that this is
  a return AND understand the value being constructed.
   Mark it with the
  same comment block as any other concept-introducing line.
- a **statement inside a function body** that uses any language feature
  without a 1:1 TS analogue (pointers,
   lifetimes,
   channels,
   `defer`,
  `with`,
   list comprehensions,
   destructors,
   ownership moves,
   `await` on a
  non-Promise type,
   range-indexing like `s[1..n]`,
   byte literals `b'/'`,
  type-annotated `let` bindings like `let x: Vec<T> = ...`,
   `let _ = ...`
  discard,
   etc.)
- a line containing punctuation a TS dev would not recognise:
   `<<`,
   `::`,
  `&`,
   `*`,
   `?`,
   `!`,
   `<...>` template args,
   `mut`,
   `'a` lifetimes,
  `->` return type arrows in non-TS positions,
   etc.

Lines that **do not** need a comment:
 closing braces,
 blank lines,
 plain
arithmetic whose TS equivalent is character-identical (`x + 1`),
 and
re-assignments to an already-commented variable using only TS-native
operators.

**Full block on a concept's first occurrence in each file.
** The first time a concept appears in a file (`?`,
 `Some(...)`,
`.to_string()`,
 an `&` argument,
 `match r { Ok(_) => ..., Err(_) => ... }`,
…),
 give it the entire What / Why / TypeScript-pseudocode block.

**Later occurrences of that same concept in that same file take one short
line.
** Say what this particular line does and move on.
 Do not restate the
concept itself:
 the reader met it above,
 in this same file.

The scope is **per file**,
 not per package,
 not per session,
 and not per
crate.
 A new file starts over at full density,
 because a reader may open it
first and has no obligation to have read any sibling.

Two concepts are **the same** when the explanation would be the same sentence.
`Ok(...)` and `Err(...)` are one concept.
 `.to_string()` and `.clone()` are
two,
 because one converts a type and the other duplicates ownership.
 When
in doubt,
 treat them as different and write the full block.

What this trades away is repetition of the *explanation*,
 not clarity,
 which
is still the deliverable.
 If a file becomes unreadable from the comment
density,
 **make the file smaller**,
 do not thin out the first-occurrence
blocks.

## Comment template

Every concept-introducing line gets a comment block above it,
 written in
whichever of the language's comment forms fits the line's role.
 Do not assume a
plain line comment:

- A **documentable declaration** (function,
   type,
   field,
   variant,
   module,
  constant,
   import,
   and so on) in a language that has **doc comments** takes the
  block AS a doc comment,
   so the one block is also the item's API documentation:
  in Rust,
   `///` above the item and `//!` at the top of the file;
   the equivalent
  in other languages.
   Write the block once,
   in the doc-comment form.
   Never leave
  it as a plain comment and bolt a separate one-line summary on top,
   and never
  keep both a plain block and a doc-comment summary for the same item.
- **Everything else** (statements and expressions inside a body,
   and languages
  with no doc comments) takes an ordinary comment:
   `//` in C / C++ / Rust / Go /
  Java / Swift / Kotlin,
   `#` in Python / Ruby / Elixir,
   `--` in Haskell / Lua /
  SQL,
   `;` in Lisp / Clojure.
   Where a doc comment on a non-item is an error
  (Rust `///` on a statement),
   this ordinary comment is the only legal choice.

The block's fields are the same whichever comment form carries it:

- **What:
  ** name the construct in plain English.
   No jargon.
   If jargon is
  unavoidable (e.g. "preprocessor",
   "namespace"),
   define it in the same
  sentence.
   Two or three lines is fine — exhaustively name every symbol on
  the line and what each one means.
  - **When the line introduces a type from a family of siblings,
    ** the
    What field must explicitly **list the siblings the reader might have
    expected**.
     Examples:
     `usize` → name `u32` / `u64` / `i32` / `i64` as
    siblings;
     `String` → name `&str` as the sibling;
     `Vec<T>` → name
    `&[T]` and `[T; N]`;
     `Box<T>` → name `Rc<T>` and `Arc<T>`;
     `i32` →
    name `u32` / `i64`.
     Just naming the type is not enough;
     the dum-dum
    reader has no way to know what alternatives even exist.
- **Why:
  ** one sentence on what the **program** gains from this line.
   Not
  "declares X" — "we need this so the next line can do Y".
  - **When the line introduces a type from a family of siblings,
    ** the Why
    field must explicitly **justify this type over the siblings named in
    What**.
     "Why `usize` and not `u64`?
    " "Why `String` and not `&str`?
    "
    "Why `Box<T>` and not `Rc<T>`?
    " One sentence each is enough;
     silence
    is not.
- **Gotcha** *(optional,
   only when warranted):
  * one line warning the reader
  when the construct **looks like** something familiar from TS but behaves
  differently (operator overloading,
   value-vs-reference,
   integer overflow,
  hoisting,
   GIL,
   ownership moves,
   …).
   Skip if there is no trap.
- A blank comment line.
- The literal lead-in `In TS you'd write (pseudocode):` — always TS,
  regardless of which language the surrounding file is in.
   The pseudocode
  block IS the TypeScript translation;
   that's the whole point.
- A fenced `` ```ts `` block (inside the language's comment syntax) holding
  the closest TS translation.
   Comments inside the block may further narrate.

Comments **never** describe the next line in the target language's own
jargon ("declares a `unique_ptr<T>`").
 Translate to TS-thinking:
 "an owning
reference to a heap-allocated `T` — when this variable goes out of scope,
the `T` is freed automatically".

## Worked example — C++ "hello world"

````cpp
// What:     `#include <iostream>` is C++'s "paste this file in here at
//           compile time" directive. `<iostream>` is the standard library
//           header that defines input/output streams. The `<...>` form
//           tells the compiler to look for the file in the standard library
//           directories (vs `"..."` which means "in my project").
// Why:      We need it so the `std::cout` line below is defined. Without
//           this `#include`, the file does not compile.
//
// In TS you'd write (pseudocode):
// ```ts
// // No 1:1 equivalent — TS gives you `console.log` for free.
// ```
#include <iostream>

// What:     `int main() { ... }` declares a function named `main` that
//           takes no arguments and returns an `int` (a 32-bit signed
//           integer). The `{ ... }` is the function body.
// Why:      Every C++ program must have exactly one `main`. The OS calls it
//           when the program starts; whatever it returns becomes the
//           program's exit code.
// Gotcha:   `int` is NOT TS's `number`. It is a fixed-width 32-bit signed
//           integer (range roughly ±2.1 billion). Overflow is undefined
//           behaviour — there is no auto-widening to `bigint`.
//
// In TS you'd write (pseudocode):
// ```ts
// async function main(): Promise<number> {
//   // ...body goes here...
//   return 0;
// }
// ```
int main() {
  // What:     `std::cout` is the standard "character output" stream — an
  //           object that represents the terminal's stdout. `<<` is the
  //           "stream insertion" operator: it pushes the right-hand value
  //           into the left-hand stream and returns the stream, which is
  //           why you can chain more `<<` after it. `"hello"` is a string
  //           literal. `std::endl` is a special value meaning "write a
  //           newline character AND flush the buffer to the terminal".
  // Why:      Print the word `hello` followed by a newline.
  // Gotcha:   `<<` here is OPERATOR OVERLOADING — the same `<<` symbol is
  //           bitwise left-shift on integers. C++ lets a type redefine what
  //           an operator means. TS has no such mechanism, so do not expect
  //           to see `<<` used this way anywhere in TS.
  //
  // In TS you'd write (pseudocode):
  // ```ts
  // console.log("hello");
  // ```
  std::cout << "hello" << std::endl;

  // What:     `return 0;` ends the function and hands the value `0` back to
  //           whoever called it. For `main` specifically, the caller is the
  //           operating system, and `0` is the convention for "program
  //           succeeded".
  // Why:      Tell the OS the program finished without error.
  //
  // In TS you'd write (pseudocode):
  // ```ts
  // return 0;
  // ```
  return 0;
}
````

In this 4-line program the comments outweigh the code roughly 15:1.
 **That
is the intended ratio.
** Other languages follow the same template by
analogy;
 only the comment form changes:
 a plain `//` / `#` / `--` / `;`
comment,
 or the language's doc-comment form when the block sits above a
documentable declaration.
 The lead-in stays `In TS you'd write (pseudocode):`
regardless of source language,
 because the pseudocode block always contains
TypeScript.

If a real file feels too verbose,
 the answer is to make the file smaller
(split into more functions,
 more files),
 **not** to thin out the comments.

## Anti-patterns drawn from real failures

These cases are taken from a real session where the skill was followed
loosely.
 Each shows the **bad** output the agent produced and the **good**
output the skill demands.
 Internalise the pattern,
 not just the specific
construct.

### Plain comment block with a stub doc comment bolted on (the rustdoc case)

Bad — the dum-dum block is written as plain `//` comments,
 then a separate,
name-derived doc comment is bolted on only to satisfy a "every item needs a doc
comment" lint:

````rust
// What:     `const CEILING: f32 = ...` is the -1 dBTP linear-amplitude ceiling.
// Why:      Normalised output must never exceed it.
//
// In TS you'd write (pseudocode):
// ```ts
// const CEILING = 0.891;
// ```
/// Ceiling.
const CEILING: f32 = 0.8912509;
````

Good — the block itself is the doc comment (`///`),
 so the one block both
satisfies the lint and documents the item;
 there is no second summary:

````rust
/// What:     `const CEILING: f32 = ...` is the -1 dBTP linear-amplitude ceiling.
/// Why:      Normalised output must never exceed it.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const CEILING = 0.891;
/// ```
const CEILING: f32 = 0.8912509;
````

The `/// Ceiling.` line only restates the name and splits the documentation into
a real block plus a hollow summary.
 For a statement inside a function body (not a
documentable item) the block stays plain `//`,
 because a doc comment there is a
compile error.

### Bare wrapper-constructor tail (the `Ok(rules)` case)

Bad — no comment on the function's tail expression because "it's just
wrapping a value":

```rust
fn load_rules(path: &str) -> Result<Vec<Rule>, String> {
    // ... body with comments ...
    Ok(rules)
}
```

Good:

````rust
fn load_rules(path: &str) -> Result<Vec<Rule>, String> {
    // ... body with comments ...
    // What:     `Ok(rules)` constructs the success variant of `Result`,
    //           wrapping our `Vec<Rule>`. No trailing `;` means this is
    //           the function's tail expression — Rust auto-returns it.
    // Why:      Hand the freshly loaded rules to the caller and signal
    //           "no error".
    //
    // In TS you'd write (pseudocode):
    // ```ts
    // return rules;
    // ```
    Ok(rules)
}
````

### Type-conversion on a literal (the `.to_string()` case)

Bad — `.to_string()` slipped in unexplained on a string literal:

```rust
return Err("no rules loaded".to_string());
```

Good:

````rust
// What:     `Err("...".to_string())`. `Err` is the failure variant of
//           `Result`. The literal `"no rules loaded"` has type
//           `&'static str` — a borrowed slice of bytes baked into the
//           binary at compile time. `.to_string()` allocates a fresh,
//           OWNED `String` whose contents are copied from that slice.
// Why:      The function signature is `Result<_, String>`, so the error
//           channel must contain an owned `String`, not a borrowed
//           `&str` — the caller may keep the error past our stack frame.
//
// In TS you'd write (pseudocode):
// ```ts
// throw new Error("no rules loaded");
// ```
return Err("no rules loaded".to_string());
````

### `Some(...)` at function tail (the `Some(escape_literal(trimmed))` case)

Bad — silent because "it's obviously the return":

```rust
fn parse_rule_source(line: &str) -> Option<String> {
    // ... body ...
    Some(escape_literal(trimmed))
}
```

Good:

````rust
fn parse_rule_source(line: &str) -> Option<String> {
    // ... body ...
    // What:     `Some(escape_literal(trimmed))` constructs the present
    //           variant of `Option`, wrapping the escaped string. Tail
    //           expression, so it's the return value.
    // Why:      The trimmed line is a plain literal; we escape it and
    //           hand it back as "yes, here is a rule source".
    //
    // In TS you'd write (pseudocode):
    // ```ts
    // return escapeLiteral(trimmed);
    // ```
    Some(escape_literal(trimmed))
}
````

### Unwrap-with-fallback (the `.unwrap_or(false)` case)

Bad — silently appended to a method chain:

```rust
if !combined.is_match(&content).unwrap_or(false) {
    return Ok(false);
}
```

Good:

````rust
// What:     `combined.is_match(&content)` returns `Result<bool, RegexError>`.
//           `.unwrap_or(false)` extracts the inner `bool` if the result
//           is `Ok`, otherwise substitutes `false` and DROPS the error.
//           `&content` borrows the bytes read-only — we are not
//           transferring ownership to the matcher.
// Why:      Treat any regex-engine failure as "no match" rather than
//           propagating it; a corrupt input shouldn't crash the scan.
// Gotcha:   `.unwrap_or(value)` on `Result` SILENTLY discards the error
//           value. Use only when "no info, fall back" is genuinely
//           correct.
//
// In TS you'd write (pseudocode):
// ```ts
// let matched: boolean;
// try { matched = combined.isMatch(content); } catch { matched = false; }
// if (!matched) return false;
// ```
if !combined.is_match(&content).unwrap_or(false) {
    return Ok(false);
}
````

### Type-choice rationale (the `usize` / `String` case)

Bad — names `usize` and `String` without saying why these and not the
siblings:

```rust
// What:     `struct Rule { ... }` with `index` (usize), `src` (String),
//           `regex` (Regex).
// Why:      We keep one Rule per forbidden-string entry.
struct Rule { index: usize, src: String, regex: Regex }
```

Good:

````rust
// What:     `struct Rule { ... }` declares a record type with three OWNED
//           fields:
//           - `index: usize`. `usize` is the unsigned integer wide enough
//             to address any byte in memory on this platform (32 bits on
//             a 32-bit OS, 64 bits on a 64-bit OS). Siblings the reader
//             might expect: `u32`, `u64`, `i32`, `i64`.
//           - `src: String`. `String` is a heap-allocated growable UTF-8
//             buffer that THIS struct owns. Sibling: `&str`, a borrowed
//             view that doesn't own its bytes.
//           - `regex: Regex`. An owned compiled regex object.
// Why:      - `index` uses `usize` (not `u32`/`u64`) because every std
//             API that takes a "size" or "index" wants `usize`; mixing
//             widths forces casts everywhere.
//           - `src` uses `String` (not `&str`) because the struct
//             outlives the function that read the file; a borrowed slice
//             would dangle.
//           - `regex` is owned for the same outlive reason.
//
// In TS you'd write (pseudocode):
// ```ts
// type Rule = { index: number; src: string; regex: Regex };
// // TS has no owned/borrowed distinction (everything is GC'd), so the type-choice
// // question does not arise.
// ```
struct Rule { index: usize, src: String, regex: Regex }
````

## Anti-patterns

- Reaching for an idiomatic-but-opaque construct because it is "the way" in
  that language (Rust iterator chains,
   Python list comprehensions,
   Go
  interface satisfaction by name,
   Kotlin scope functions).
- Dropping the **pseudocode** block because "the code is obvious".
   It is
  not obvious to this user,
   and it is mandatory on every block.
- Skipping **What** on a symbol-heavy line.
   If the line contains `<<`,
  `::`,
   `&`,
   `*`,
   `?`,
   `!`,
   `<...>`,
   `mut`,
   lifetimes,
   or any punctuation a
  TS dev would not recognise,
   name and explain each piece individually.
- Skipping a comment block on a **bare tail expression** (`Ok(rules)`,
  `Some(x)`,
   `(line, col)`,
   `if ... { a } else { b }` at end of fn).
   The
  tail IS the return;
   it always needs the full block.
- Skipping a comment block on a **wrapper constructor or unwrap chain**
  (`Some(...)`,
   `None`,
   `Ok(...)`,
   `Err(...)`,
   `.to_string()`,
  `.unwrap_or(...)`,
   `.ok()`,
   `.clone()`,
   `?`) on its **first**
  appearance in a file because it appeared a few lines up in a different file.
   The first-occurrence rule is scoped per file;
   later occurrences within
  that same file do take the short form.
- Naming a type without **naming its siblings and justifying the choice**.
  `usize` without "(not `u32`/`u64`/`i64`)";
   `String` without "(not
  `&str`)";
   `Box<T>` without "(not `Rc<T>`/`Arc<T>`)".
   The dum-dum reader
  has no way to know a sibling exists.
- Comments that describe the next line in the target language's own jargon
  ("declares a `unique_ptr<T>`").
   Translate to TS-thinking instead.
- Combining several lines under one comment block.
   One concept-introducing
  line ↔ one comment block,
   even if it gets repetitive.
- Removing comments later to "tidy up".
   The comments **are** the
  deliverable.
- Padding **Why** with a restatement of **What**.
   If `Why:` does not say
  what the program gains,
   delete it and write a real one.

## Out of scope

This skill does not apply when:

- the file is `.ts`,
   `.tsx`,
   `.js`,
   `.jsx`,
   `.mjs`,
   `.cjs`
- the file is a declarative or data format:
   `.html`,
   `.css`,
   `.scss`,
  `.json`,
   `.yaml`,
   `.yml`,
   `.toml`,
   `.sql`,
   `Dockerfile`,
   `mise.toml`,
  `package.json`,
   etc.
- the file is generated (auto-produced by a tool,
   marked `DO NOT EDIT`,
  vendored from a third party)
- the change is a single-character or mechanical edit in an existing non-TS
  file (rename,
   typo fix) where adding the comment template would dwarf
  the change.
   In that case,
   match the surrounding comment density instead.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…