News for hackers. Stuff that matters.
Re:Local Variables as Accidental Breadcrumbs for Faster Debu... by jph on Thursday October 10, 2024 @02:15PM (#41801600)
> add assertions to your code.

Yes, and many programming languages have assertions such as "assert greater than or equal to".

For example with Rust and the Assertables crate:

    fn calculate_something() -> f64 {
        let big = get_big_number();
        let small = get_small_number();
        assert_ge!(big, small); // >= or panic with message
        (big - small).sqrt
    }
It turns out it's even better if your code has good error handling, such as a runtime assert macro that can return a result that is NaN (not a number) or a "maybe" result that is either Ok or Err.

For example with Rust and the Assertables crate:

    fn calculate_something() -> Result(f64, String) {
        let big = get_big_number()
        let small = get_small_number()
        assert_ge!(big, small)?; // >= or return Err(message)
        (big - small).sqrt
    }
Re:Local Variables as Accidental Breadcrumbs for Faster Debu... by aftbit on Thursday October 10, 2024 @06:14PM (#41804112)
Is there a reason you need specialized assertions over something like Python's generic assert?

    >>> big = 2; small = 3
    >>> assert big >= small, "big is smaller than small"
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AssertionError: big is smaller than small

In pytest, assertions are rewritten[1] to return something more useful like:

        def test():
            big = 2
            small = 3
    >       assert big > small
    E       assert 2 > 3
    
    test/test_dumb.py:4: AssertionError
    ========== short test summary info ==========
    FAILED test/test_dumb.py::test - assert 2 > 3

1: https://github.com/pytest-dev/pytest/blob/f373974707f57a0b28...
Re:Local Variables as Accidental Breadcrumbs for Faster Debu... by Arnavion on Thursday October 10, 2024 @06:31PM (#41804234)
Rust has a generic assert too `assert!(foo >= bar);`. I assume (haven't used the crate myself) the advantage of `assertable::assert_ge!(foo, bar)` is that it prints the values of foo and bar in the assert message. The `assert_eq!(foo, bar)` and `assert_ne!(foo, bar)` macros provided by Rust libstd also do this. But the generic `assert!()` just sees the boolean result of its expression and only prints that in its message.

The values of the variables can be included in the generic macro's message via a custom message format, like `assert!(foo >= bar, "foo = {foo}, bar = {bar}");` but having the macro do it by default is convenient. There is an old discussion to have the `assert!()` macro parse its expression to figure out what variables are there and print them out by default, but it's still WIP. ( https://github.com/rust-lang/rfcs/blob/master/text/2011-gene... https://github.com/rust-lang/rust/issues/44838 )

Re:Local Variables as Accidental Breadcrumbs for Faster Debu... by o11c on Thursday October 10, 2024 @07:00PM (#41804433)
What's more, pytest errs on the side of "just capture more" and In my experience it's quite useful:

  ============================= test session starts ==============================
  platform linux -- Python 3.11.2, pytest-7.2.1, pluggy-1.0.0+repack
  rootdir: /tmp/dl/py
  collected 1 item                                                               
  
  test_bigsmall.py F                                                       [100%]
  
  =================================== FAILURES ===================================
  ________________________________ test_something ________________________________
  
      def test_something():
  >       assert get_big_number() > get_small_number()
  E       assert 0 > 1
  E        +  where 0 = get_big_number()
  E        +  and   1 = get_small_number()
  
  test_bigsmall.py:8: AssertionError
  =========================== short test summary info ============================
  FAILED test_bigsmall.py::test_something - assert 0 > 1
  ============================== 1 failed in 0.06s ===============================
Re:Local Variables as Accidental Breadcrumbs for Faster Debu... by lispm on Friday October 11, 2024 @06:17AM (#41808107)
Or even better have the assertion offer a way to repair the problem:

    CL-USER 1 > (defun calculate-something (big small)
                  (assert (>= big small)
                      (big small)           ; these can be reset
                    "Big ~a must be bigger than small ~a" big small)
                  (sqrt (- big small)))
    calculate-something
The error handling will now offer me to repair it, if necessary:

    CL-USER 2 > (calculate-something 4 7)

    Error: Big 4 must be bigger than small 7
      1 (continue) Retry assertion with new values for BIG, SMALL.
      2 (abort) Return to debug level 0.
      3 Restart top-level loop.

    Type :b for backtrace or :c <option number> to proceed.
    Type :bug-form "<subject>" for a bug report template or :? for other options.

    CL-USER 3 : 1 > :c 1 
    The old value of BIG is 4.
    Do you want to supply a new value?  yes

    Enter a form to be evaluated:
    17

    The old value of SMALL is 7.
    Do you want to supply a new value?  yes

    Enter a form to be evaluated:
    5

    3.4641016
The last number is the return value