Setter Method (Assignment) with Multiple Arguments

Setter method (assignment) with multiple arguments

Due to the syntax sugar of methods whose names end in=, the only way that you can actually pass multiple parameters to the method is to bypass the syntax sugar and use send

h.send(:strategy=, :mystrategy, :backward )

…in which case you might as well just use a normal method with better names:

h.set_strategy :mystrategy, :backward

However, you could rewrite your method to automatically un-array the values if you knew that an array is never legal for the parameter:

def strategy=( value )
if value.is_a?( Array )
@strategy << value.first
@strategy.direction = value.last
else
@strategy = value
end
end

This seems like a gross hack to me, however. I would use a non-assigment method name with multiple arguments if you need them.


An alternative suggestion: if the only directions are :forward and :backward what about:

def forward_strategy=( name )
@strategy << name
@strategy.direction = :forward
end

def reverse_strategy=( name )
@strategy << name
@strategy.direction = :backward
end

Passing multiple parameters to Setter method using assignment expression

Separating values by comma without enclosing then in square brackets - [] - in Python, actually creates a tuple, not a list.

In fact, due to dynamic typing in Python, it is not considered a good practice to check exactly for a "list", when any sequence, or even iterable, will work equally well.

The second thing is that properties are meant to enable a single argument passing. Only the param parameter in your function will be used - the second parameter, use_type will not be passed by the property mechanism.

That means you have to read your arguments explicitly inside your method code, and a little extra logic is needed so that use_type is actually optional.

Actually, if you want to parametrize the settings of tokens with more than an argument, my advice would be to, in this case, just use a plain setter method, instead of resorting to properties or other descriptors. This will cause less surprise for people viewing (or having to write) code that use this class and set .tokens:

class Question:
...
def __init__(self, ...):

self.token = ... # Plain, unguarded attribute
..
def set_token(self, value, use_type = None):
...


But if you really want a property that will accept a sequence, with the second value being optional. However, if you are really using typing annotations and enforcing then, you have to restrict your params to tuples (which fortunately is the data type created by Python when you just separate objects by , as is in your code)

class Question:
...
@token.setter
def token(self, params: typing.Tuple[typing.Any, typing.Optional[bool]):
"""params should be a 1-or-2 tuple, with the second item, if present
a bool indicating "use_type"
"""
# The operation bellow will raise TypeError
# if params is not a tuple, so no need for the explicit check -
# just let the error propagate
value, use_type, *_ = params + (False,)
# if only one item is passed, "False" ends up in "use_type".
# With 2 itens, the extra "False" is assigned to "_" indicating
# it should be disregarded (it is a Python convention for '_' as a variable name)
if use_type:
...

And with this your question.tokens = tokens, True expression will work, as will
question.tokens = tokens,, but not question.tokens = tokens - as in this case, the value is not a tuple; (if it is a tuple it will be incorrectly used inside the method body as is) - I will say again that this is a strange pattern, and an explicit setter method should be preferred.

Creating a setter method that takes extra arguments in Ruby

It doesn't work because the parser doesn't allow it. An equals sign is allowed in expressions of the form identifier = expression, expression.identifier = expression (where identifier is \w+), expression[arguments] = expression and expression.[]= arguments and as part of a string or symbol or character literal (?=). That's it.

gen.send(:allow=, 'a', 1, false) would work, but at that point you could as well just give the method a name that doesn't include a =.

Property setter with multiple values


How do I pass two values to the setter?

You can pass an iterable(tuple, list) to the setter, for example:

class A(object):
def __init__(self, val):
self.idx = val

@property
def idx(self):
return self._idx

@idx.setter
def idx(self, val):
try:
value1, value2 = val
except ValueError:
raise ValueError("Pass an iterable with two items")
else:
""" This will run only if no exception was raised """
self._idx = sha512(value1+value2)

Demo:

>>> a = A(['foo', 'bar'])     #pass a list
>>> b = A(('spam', 'eggs')) #pass a tuple
>>> a.idx
<sha512 HASH object @ 0xa57e688>
>>> a.idx = ('python', 'org') #works
>>> b.idx = ('python',) #fails
Traceback (most recent call last):
...
raise ValueError("Pass an iterable with two items")
ValueError: Pass an iterable with two items

Multiple Parameters for Object.defineProperty Setter Function?


Is it possible to have multiple parameters for Object.defineProperty setter function?

Yes, but it's not possible to invoke them (other than Object.getOwnPropertyDescriptor(obj, "joe").set(null, false)). A setter is invoked with the one value that is assigned to the property (obj.joe = "doe";) - you cannot assign multiple values at once.

If you really need them (for whatever reasons), better use a basic setter method (obj.setJoe(null, false)).

Kotlin setter with multiple arguments

That's not possible due to the way that setter functions work - they only take a single argument. Even if you think about the usage of a setter with multiple arguments, it wouldn't look right:

x.data = items, { /** listener impl */ }

If you really wanted to, you could group your arguments into a single object:

x.data = Wrapper(items, { /** listener impl */ })

But even that suggestion isn't nice. The nicest in my opinion is what you consider to be inelegant, using a Java style setter (which isn't a typical setter since it has multiple arguments), but at least Kotlin gives you a nicer call syntax:

x.setData(items) { /** listener impl */ }

Ruby, how to overwrite the setter ( = ) method to allow 2 parameters?

As @eugen correctly says, you cannot pass two arguments to a setter like

self.my_vector = 1, 2

The nearest thing you can achieve is to unpack the argument using pattern matching:

def myvector=(arg)
arg => [x, y]
@my_vector = Vector2d.new(x, y)
end

foo.my_vector = [1, 2]

An alternative is to define a simple helper method v so you can write

foo.my_vector = v 1, 2

Why use setter when you can assign massively using a method?

Typically, the targets of getters and setters are made private so they're not directly accessible from outside of the file or library.

class Business {
String name, _address;
double lat, long;
bool coordsCalculated = false;
Map propertyRecords = {};

get address {
return _address;
}

set address(String address) {
if (address == _address) return; // Nothing changed;
_address = address;
// API call to calculate lat/log
APICall(onSuccess: (data) {
lat = data.lat;
long = data.long;
coordsCalculated = true;
});
}

void rewrite(String name, String address) {
this.name = name;
this.address = address;
}

String summary() {
if (coordsCalculated) return "Business name is $name, here's a link to the map!";
return "Business name is $name, at $_address.";
}

Human(this.name, String address) {
this.address = address;
}
}

The user of the class feels like they're using a normal property, but it does other silent things.

Methods can do this too, yes, but this can feel cleaner.

Importantly, getters and setters cannot be asynchronous which definitely can give methods an advantage, but there are plenty of valid uses.

Getters and setters are also easier to read, when being used. Less parentheses are always a good thing.

You certainly don't need to always use them, or use them when they do nothing but set the variable, but they can be nice.

In one of my Widgets, I have a getter that looks something like

FileState get fileState => FileUploaderKey.currentState!. widget.file.state;

It's so much easier to read this way. It gets the current state of the file, always, whereas

FileState fileState = FileUploaderKey.currentState!.widget.file.state;

Only saves the current state, but doesn't change with it.



Related Topics



Leave a reply



Submit