{"record":{"id":"098a35686444000d","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-098a35","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/atom.rb","lineNumber":158,"sourceCode":"    # of side effects.\n    #\n    # @note The given block may be called multiple times, and thus should be free\n    #   of side effects.\n    #\n    # @param [Object] args Zero or more arguments passed to the block.\n    #\n    # @yield [value, args] Calculates a new value for the atom based on the\n    #   current value and any supplied arguments.\n    # @yieldparam value [Object] The current value of the atom.\n    # @yieldparam args [Object] All arguments passed to the function, in order.\n    # @yieldreturn [Object] The intended new value of the atom.\n    #\n    # @return [Object] The final value of the atom after all operations and\n    #   validations are complete.\n    #\n    # @raise [ArgumentError] When no block is given.\n    def swap(*args)\n      raise ArgumentError.new('no block given') unless block_given?\n\n      loop do\n        old_value = value\n        new_value = yield(old_value, *args)\n        begin\n          break old_value unless valid?(new_value)\n          break new_value if compare_and_set(old_value, new_value)\n        rescue\n          break old_value\n        end\n      end\n    end\n\n    # Atomically sets the value of atom to the new value if and only if the\n    # current value of the atom is identical to the old value and the new\n    # value successfully validates against the (optional) validator given\n    # at construction.\n    #","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/atom.rb#L140-L176","documentation":"Concurrent::Atom#swap atomically replaces the atom's value with the result of a block that receives the current value (plus any passed arguments) and returns the intended new value. The block is the update function itself, so swap raises ArgumentError immediately when called without one, before the compare-and-set loop starts.","triggerScenarios":"`atom.swap` with no block; passing a Proc as a positional argument `atom.swap(updater)` instead of as a block `atom.swap(&updater)`; helper methods that accept an updater but forget to forward it with `&`.","commonSituations":"Refactoring from `atom.value = compute` to a compare-and-set swap; dynamic updater selection where the chosen Proc is dropped; metaprogramming (define_method/instance_exec) losing the block; code copied from examples that omit the block.","solutions":["Call swap with a literal block: `atom.swap { |v| v + 1 }` — extra arguments come after the value: `atom.swap(2) { |v, step| v + step }`.","When the updater is a Proc or Method object, convert it: `atom.swap(&updater)`.","If you only want an unconditional write, use `atom.reset(new_value)` or `atom.value = new_value` instead of swap.","Audit helper methods: every def that forwards to swap must capture and forward the block (`def bump(&blk) atom.swap(&blk) end`)."],"exampleFix":"// before\nupdater = ->(v) { v + 1 }\natom.swap(updater)   # ArgumentError: no block given\n\n// after\natom.swap(&updater)  # or: atom.swap { |v| v + 1 }","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'swap requires an updater block' unless block_given?\natom.swap { |v| v + 1 }","typeGuard":"def callable_updater?(obj)\n  obj.respond_to?(:call)\nend\n\natom.swap(&updater) if callable_updater?(updater)","tryCatchPattern":"begin\n  atom.swap(&updater)\nrescue ArgumentError => e\n  raise unless e.message == 'no block given'\n  logger.error('Atom#swap called without a block')\n  raise\nend","preventionTips":["Always convert stored Proc/Method updaters with & when calling swap or try_update.","Use atom.value = for plain writes; reserve swap for read-modify-write cycles.","Treat the block as part of swap's signature in any wrapper: def bump(&blk) atom.swap(&blk) end."],"tags":["concurrent-ruby","atom","block","argumenterror"],"backgroundTag":"no-block-given","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}