'this' in js and 'self' in python - data-structures

The code to create a Set class in JS from a lesson Ive been working on uses !this.has(element)...in the add method. In the next line, it doesnt use 'this'. I am wondering when I am supposed to use 'this' on its own as in the add method or use it as 'this.variableName' or simply use the variable name on its own. I have the same questions about the methods in data structure classes in python only with 'self'. At times it uses self.variableName and other times not. Can anyone explain this to me? Thank you

self in python and this in JS are equivalent.
Both mean the class instance. When using self, you are explicitly using the class property against another property that can have the same name. Eg:
class MyClass:
value: int
def __init__(self, value):
self.value = value
def sum(self, value):
return self.value + value
myClass = MyClass(5)
print(myClass.sum(3)) # prints 8. In the sum method, self.value = 5 and value = 3.

Related

How to create "#property" and "#property=" that are actually methods

Is there were a way to make an #property into a method with set and get, so, #property would call a method instead of returning an actual property, and #property = someval would also call a method instead of assigning to an actual property?
In my project, objects store values in a database. Consider this simple database module that stores records in memory. In my real life project it's a DBM like PostgreSQL:
module MyDB
RECORDS = {}
def self.create(pk)
RECORDS[pk] ||= {}
end
def self.set(pk, key, val)
return RECORDS[pk][key] = val
end
def self.get(pk, key)
return RECORDS[pk][key]
end
end
Objects have fields that are stored in that database. So, in this class, the species field is stored in and retrieved from the database:
class Pet
def initialize(pk)
#pk = pk
MyDB.create(#pk)
end
def species=(val)
MyDB.set #pk, 'breed', val
end
def species()
return MyDB.get(#pk, 'breed')
end
end
A simple use of the Pet class could look like this:
motley = Pet.new('motley')
motley.species = 'cat'
It works currently, but here's where I ran into an annoyance. I did something like this within the class:
def some_method(newval)
#species = newval
end
Then, when I ran the code I got this result:
motley.some_method 'whatever'
puts motley.species #=> cat
Then I realize that wasn't corrent and what I should have done is:
def some_method(newval)
self.species = newval
end
I think #species = newval makes sense. It feels like I'm setting a property of the object.
Is were a way to assign a method to the property, something like:
def :#species=(val)
return MyDB.set(#pk, 'breed', 'val')
end
def :#species
return MyDB.get(#pk, 'breed')
end
Is there a way to do such a thing? Should there be?
Is there a way to do such a thing?
No. In Ruby setter and getter methods are the way to get/set the internal state of an object. Instance variables are just lexical variables that are scoped to an instance.
Ruby is a language based on message passing and #foo = bar sends the message =, bar to the recipient that is the lexical variable #foo. If it called self##foo= instead that would break the entire model of the language.
Should there be?
Hell no.
Do we really need a completely new language feature just because you find it hard to remember to call self.foo= instead of #foo =? No.
Would this feature add anything to the language that cannot already be done? No.
Would it break existing code? Yes.

Ruby syntax for declaring an lvalue / rvalue = operator

I am trying to build an equals function in Ruby. What I want to do is something like this, suppose we have a class called A:
class A
attr_accessor :secret_datum
def public_datum
return secret_datum
end
def public_datum= what
secret_datum = what
end
end
What I want basically is to build a more complex behind the scenes functionality depending on whether public_datum is used as an lvalue or an rvalue, but my code above does not work:
2.5.0 :027 > a = A.new
=> #<A:0x00007fc2293ec338>
2.5.0 :028 > a.public_datum = 7
=> 7
2.5.0 :029 > a.public_datum
=> nil
What is the correct syntax for declaring such a set of functions?
When assigning a value to a bareword with secret_datum = what, you are always setting a simple local variable.
It seems that you actually want to use the setter of your class (which then sets the instance variable). For that, you have to hint to Ruby that you want to call the method. You can do this by defining a receiver object. Your setter can thus look like this:
def public_datum=(what)
self.secret_datum = what
end
Alternatively, you could directly set the instance variable as follows:
def public_datum=(what)
#secret_datum = what
end
As a final note, please be aware that your secret_datum accessor is still public. Thus, you could also call a.secret_datum = 7 and it would work exactly the same.
An instance variable is declared with a prepended "#" like
#secret_datum = what
Without the # the variable is declared on the stack and gone when you exit the function.
So just refer to the instance variable as #secret_datum and it will work
def public_datum=(what)
#secret_datum = what
end

Saving instance list in class variable

I want to store newly created Person instance inside the class variable objects, but not sure how to reference the current instance from the constructor.
class Person
##objects = {}
def initialize(key)
##objects[key] = something
end
Ideally, the result is to be able to access the dictionary of Person objects through Person.objects
Simply, in constructor function, self will refer to the current instance.
class Person
##objects = {}
def initialize(key)
##objects[key] = self
puts self # it will print the id of the current instance
end
end
Same way, if you write self in a class method, it will refer to the the class.
But from your question, you seem to be doing something like Person.objects, and it won't work, and will output the following line:
NoMethodError: undefined method `objects' for Person:Class
So, you need to write a class method for it to let the outside world access objects.
def self.objects
##objects
end
Well, there are other ways as well to access the class variables, please have a look at this question.

How to define a Class method like MyObject[:test]= 'test'

This is what I want do create, but it doesnt work:
class MyObject
def self.[]=(key, value)
##internal_hash[key] = value
end
end
I don't understand why overriding the self dot bracket doesnt work.
You need to initialize the class variable.
class MyObject
##internal_hash = {}
def self.[]=(key, value)
##internal_hash[key] = value
end
end
This is for two reasons.
Instance variables can be used without initialization, but class variables cannot.Programming Ruby:Class Variables and Class Methods:Class Variables:1st paragraph
Even if a class variable was able to be used without initialization, it would be implicitly initialized to nil, and you cannot suddenly use the Hash#[] method.

Ruby Custom Super Initialization

Here is my situation:
XMLRPC::Client has a proxy constructor, new3, that takes a hash of options. It takes out the individual values to then delegate the construction to the default initializer, initialize
I am deriving from XMLRPC::Client. I want a class that is XMLRPC::Client but with some added functionality.
I want to be able to instantiate this derived class using a hash of options as well. This means that in my derived class' initializer, I have to somehow instantiate super using the new3 proxy constructor.
My Question Is if this is possible. If not, then is the only way to solve this is to practically 'copy and paste' the code within the XMLRPC::Client.new3 method into my derived class' constructor?
The reason I'm asking this is simply to see if there is a way of solving this problem, since there is this recurring theme of DRY (Don't Repeat Yourself) within the Ruby community. But of course, if this is the only way, it wont kill me.
I am only posting an answer supplement the other answers by showing you how XMLRPC's code is written
def new3(hash={})
# convert all keys into lowercase strings
h = {}
hash.each { |k,v| h[k.to_s.downcase] = v }
self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'],
h['use_ssl'], h['timeout'])
end
http://www.ensta.fr/~diam/ruby/online/ruby-doc-stdlib/libdoc/xmlrpc/rdoc/classes/XMLRPC/Client.html
Make a new class method in your derived class (much like they did to make new3 in the first place):
class MyDerived < XMLRPC::Client
def self.new3(hashoptions)
client = XMLRPC::Client.new3(hashoptions)
# Do further initialisation here.
end
end
myone = MyDerived.new3(:abc => 123, ...)
super only works in initialize (and only changes the parameters to the superclass's initialize), so it doesn't apply here.
You should probably be able to call new3 on you subclass
class MyClient < XMLRPC::Client
end
MyClient.new3({})
Or overwrite it if you need to do extra stuff:
class MyClient < XMLRPC::Client
def self.new3(args)
client = super(args)
# do some more stuff
client
end
end
MyClient.new3({})

Resources