The difference is that by putting it in the arguments, you allow the caller to provide different values, versus hard-coding them. For example:
def initialize(discount=0, total=0, items=[])
@total = total
@discount = discount
@items = items
end
Now you can call it with no arguments, or you can specify the arguments:
MyClass.new
# uses all defaults
MyClass.new(123)
# Uses custom value for discount only
MyClass.new(1, 2, ["item"])
# Uses custom values for all
The problem with this approach, is what happens when you want to give a custom value for total (the second argument) but use the default value for discount (the first)? With positional arguments, you can't. So it's preferred to use keyword arguments instead:
def initialize(discount: 0, total: 0, items: [])
Now you can specify custom values for any combination of the three arguments, for example:
MyClass.new
# uses all defaults
MyClass.new(total: 123)
# this uses default values for discount and items