Skip to content

Explicit Discard (discard)

Profile: :core and above
Purpose: Explicitly discard the result of an expression
Motivation: Clear, readable code that signals intent to ignore return values


When calling functions for their side effects, you often don’t care about the return value. In many languages, this is implicit and potentially dangerous:

// C: Return value silently ignored
write(fd, buffer, size); // Did it succeed? Who knows!

In Zig, you use _ = expr to explicitly discard:

// Zig: Explicit but cryptic
_ = posix.close(fd);
_ = allocator.free(buf);

The _ syntax is concise but not self-documenting. Newcomers often don’t understand what it means.


Janus uses the discard keyword for explicit clarity:

// Janus: Explicit and readable
discard posix.close(fd)
discard allocator.free(buf)

The word “discard” makes the intent obvious: “I am intentionally ignoring this result.”


discard expression

The discard keyword evaluates the expression and discards its result. This is useful for:

  1. Side-effect only functions
  2. Fire-and-forget async tasks
  3. Logging and debugging output

// Close a file descriptor, ignore return code
discard posix.close(fd)
// Free memory, ignore success/failure
discard allocator.free(buf)
// Write log message, ignore bytes written
discard logger.write("Application started")

You can combine discard with error handling to ignore success values but handle errors:

discard may_fail() catch |err| do
log_error("Operation failed:", err)
end
// Process items, discard intermediate results
for items do |item|
discard process_item(item)
end
// Cleanup sequence
discard posix.close(fd)
discard allocator.free(buf)
discard logger.write("Cleanup complete")

LanguageDiscard SyntaxNotes
Janusdiscard exprExplicit, readable
Zig_ = exprCryptic to newcomers
Rustlet _ = exprPattern discard, verbose
Go_ = exprSame as Zig
CexprSilent, dangerous

Janus still uses _ for pattern-level discards:

// Pattern discard: ignoring a value in destructuring
let (x, _, z) = tuple // Ignore middle element
// Catch discard: ignoring the error value
result catch |_| do
// Handle any error uniformly
end
// For loop discard: ignoring the index
for _ in 0..10 do
println("Hello")
end

Use discard for statement-level result discarding, _ for pattern-level binding discarding.


  • Calling functions for side effects only
  • Fire-and-forget async operations
  • Cleanup operations where you don’t care about success/failure
  • Making intent explicit to readers
// Good: Clear intent
discard logger.info("User logged in")
  • You should handle the error (use try or catch)
  • The return value contains important information
  • You’re in a pattern context (use _ instead)
// Bad: Silently ignoring errors
discard risky_operation() // Don't do this!
// Good: Handle errors explicitly
try risky_operation() catch |err| do
handle_error(err)
end

The discard keyword embodies Janus’s philosophy of Syntactic Honesty:

“Code should say what it means. _ = says ‘assign to underscore’, which is implementation detail. discard says ‘I am discarding this result’, which is intent.”

For the :core teaching profile, discard is especially valuable:

  • No cryptic symbols to memorize
  • Self-documenting code
  • Clear distinction from pattern discards (_)