Ruby Class definition explanation for a java developer [closed] - java

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am a java developer and am having hard time understanding this Ruby code, can someone please explain this code in java terms? I can understand the methods part (defs) but the belongs_to part is what confusing me
module Test
class Signature < Base
belongs_to :recipient, :class_name => 'Test::UserInformation'
belongs_to :sd_file, :class_name => 'Test::TransportFile',
:foreign_key => 'reference_id'
def sd_status
sd_file.nil? ? nil : sd_file.Status
end
def sd_sent_on
sd_file.nil? ? nil : sd_file.sent
end
def sd_received_on
sd_file.nil? ? nil : sd_file.received
end
def self.find_information(options={})
unless (start_date = options.delete(:start_date)).blank? ||
(end_date = options.delete(:end_date)).blank?
date_conditions = ' AND ' +
'(requested_at > ?) AND ' +
'(requested_at < ?)'
end

The key thing here is to realize that (almost) everything in Ruby is a script, (almost) everything in Ruby is a message send ("virtual method call" in Java-speak), and (almost) everything in Ruby is an object.
In Java, the only executable code is inside method definitions. Everything else are just declarations, directives to the compiler to create some compiler-internal data structure. A class declaration isn't executed at runtime, it is interpreted at compile time by the compiler, which then generates the corresponding class structure, methods, fields, etc.
Not so in Ruby. The content of a file is just a script that gets executed top to bottom. That's why you can, for example, have stuff like this:
if OS.windows?
class Foo
end
else
class Bar
end
end
Likewise, the body of a module or class definition is just a script, which allows you to have stuff like this:
if OS.windows?
def foo
end
else
def bar
end
end
So, as you can see, really almost everything is a script, in particular, the body of a class definition is just a script that gets executed from top to bottom, just like any other script.
By the way, since the class definition is dynamically executed at runtime and not statically interpreted by the compiler, the same goes for the superclass definition in a class definition: it is, in fact, just an arbitrary Ruby expression that returns an object that is an instance of Class, it doesn't necessarily have to be a static constant class, i.e. you can write something like this:
class Foo < if rand < 0.5 then String else Array end
end
# Yes, I am aware that this makes zero sense. Here is a more sensible example:
class Point < Struct.new(:x, :y)
end
# `Struct` is a class whose `::new` method returns a class
class Search < R '/search'
end
# This is an example from the Camping web microframework:
# `Search` is a controller which is bound to the URI route `/search`
In case you are wondering: if a class definition is just a piece of code, does it return anything? And the answer is "Yes, it does!" In fact, everything in Ruby returns something, everything is an expression in Ruby. There are no statements. Only expressions. A class definition evaluates to the value of the last expression that is evaluated inside the class definition. Typically, the last expression that is evaluated inside a class definition is a method definition (yes, a method definition is an expression just like any other, and thus also has a return value), and a method definition evaluates to the name of the method being defined, expressed as a Symbol
Also, almost everything is an object: there is a top-level global object which doesn't have a name but is usually called main (because that's what its to_s and inspect return). Everything you run at the top-level in a script happens with self (this in Java-speak) being bound to main. And classes are also objects, they are instances of the Class class. Within a class definition body, self is bound to the class that is being defined.
Now, on to "almost everything is a message send": usually, whenever you see something being "done" in Ruby, it is the result of a message send: 1 + 2 is actually 1.+(2), !false is actually false.!, foo.bar = baz is actually foo.bar=(baz), ary[idx] is actually ary.[](idx), ary[idx] = val is actually ary.[]=(idx, val) and so on and so forth.
belongs_to is no different: it is actually a message send to self, which in the context of a class definition is the class being defined. In other words, it's just calling a "class method". (Note: there aren't really class methods in Ruby, every method is an instance method. As we have already established, classes are objects like any other object, so they can have instance methods like any other object, there is no need for a special "class method" or "static method" construct!)
Let's start with an easier example:
class Foo
attr_reader :bar
end
Again, attr_reader is a message send to self, which is Foo in this case. attr_reader just generates an attribute reader (a "getter" in Java-speak). And it looks a bit like this (don't worry if you don't fully grasp Ruby Reflection yet, you should be able to follow along anyhow):
class Class # in reality, it is defined in `Module`, a superclass of `Class`
def attr_reader(name)
define_method(name) do
instance_variable_get(:"##{name}")
end
end
end
By the way: def is not a message send, it is a builtin keyword. But there is a corresponding method that can be used instead, which you see being used above: Module#define_method
In fact, Ruby doesn't even have constructors! new is just a "class method", and it looks pretty much like this:
class Class
def new(*args, &block)
new_obj = allocate
new_obj.initialize(*args, &block)
return new_obj
end
end
There are a few subtleties here, such as initialize being private by default, so that in reality we need to use reflection to circumvent access restrictions, but that's the gist of it.
Oh, and since I just mentioned private: that's a method, too, not a keyword that is interpreted as an instruction for the compiler.
So, to recap, where do we stand: a class definition is just a piece of code, method definitions are just expressions that get executed. But since a class definition is just a piece of code, there can be arbitrary code in there, including message sends ("method calls" in Java-speak). belongs_to is just a message send (method call) to the class itself, i.e. the method is defined somewhere up in the inheritance chain of the class object itself (not to be confused with the inheritance chain of instances of the class!)
But the really important takeaway is this: it is just a method call. Nothing scary. Nothing magical. Nothing special.
Now, what does this method call do?
It is part of a popular ORM library for Ruby called ActiveRecord, and it sets up an association between self (i.e. the class whose definition the call appears in) and another class whose name is provided as an argument (or to be more precise: since ActiveRecord relies a lot on conventions, the name of the class can be derived from the argument). From this association between Ruby classes, the ActiveRecord ORM will automatically deduce corresponding relations between the database tables backing those classes.
Explaining how exactly that works would amount to writing a full tutorial on ActiveRecord, which a) is just too much for a Stack Overflow answer, and b) other people have already done much better than me. But I got the impression anyway that you didn't so much want to know how belongs_to works internally, but rather how a method call can appear in what your Java-trained mind is used to being just "dead code" that doesn't get executed. And the solution to that riddle is simply: it isn't dead code and it does get executed.

belongs_to may seem like a very magical piece of ruby code, that connects your model to another, using SQL table associations.
But all it does is takes in a few hash parameters, creating series of dynamic methods.
Lets take apart
belongs_to :sd_file, class_name: 'Test::TransportFile', foreign_key: 'reference_id'
belongs_to - A methods to set up an association
sd_file - What method will be used to acess it:
Test::Signature.first.sd_file
class_name - option to specify which ruby class to load. sd_file will point to Test::TransportFile. Usually this is done automatically by rails if everything adheres to conventions. But you can specify manually
foreign_key - Key in the table which ties the two records together. This is either in Test::TransportFile or in Test::Signature (I can't remember off the top of my head). And it will tie in with the id in another table.

Related

What are 'real' and 'synthetic' Method parameters in Java?

Looking into j.l.r.Executable class I've found a method called hasRealParameterData() and from its name and code context I assume that it tells whether a particular method has 'real' or 'synthetic' params.
If I take e.g. method Object.wait(long, int) and call hasRealParameterData() it turns out that it returns false which is confusing to me, as the method is declared in Object class along with its params.
From this I've got a couple of questions:
What are 'real' and 'synthetic' Method parameters and why Java believes that params of Object.wait(long, int) are not 'real'?
How can I define a method with 'real' params?
Preamble - don't do this.
As I mentioned in the comments as well: This is a package private method. That means:
[A] It can change at any time, and code built based on assuming it is there will need continuous monitoring; any new java release means you may have to change things. You probably also need a framework if you want your code to be capable of running on multiple different VM versions. Maybe it'll never meaningfully change, but you have no guarantee so you're on the hook to investigate each and every JVM version released from here on out.
[B] It's undocumented by design. It may return weird things.
[C] The java module system restriction stuff is getting tighter every release; calling this method is hard, and will become harder over time.
Whatever made you think this method is the solution to some problem you're having - unlikely. If it does what you want at all, there are probably significantly better solutions available. I strongly advise you take one step backwards and ask a question about the problem you're trying to solve, instead of asking questions about this particular solution you've come up with.
Having gotten that out of the way...
Two different meanings
The problem here is that 'synthetic' means two utterly unrelated things and the docs are interchanging the meaning. The 4 unrelated meanings here are:
SYNTHETIC, the JVM flag. This term is in the JLS.
'real', a slang term used to indicate anything that is not marked with the JVM SYNTETHIC flag. This term is, as far as I know, not official. There isn't an official term other than simply 'not SYNTHETIC'.
Synthetic, as in, the parameter name (and other data not guaranteed to be available in class files) are synthesised.
Real, as in, not the previous bullet point's synthetic. The parameter is fully formed solely on the basis of what the class file contains.
The 'real' in hasRealParameterData is referring to the 4th bullet, not the second. But, all 4 bullet point meanings are used in various comments in the Executable.java source file!
The official meaning - the SYNTHETIC flag
The JVM has the notion of the synthetic flag.
This means it wasn't in the source code but javac had to make this element in order to make stuff work. This is done to paper over mismatches between java-the-language and java-the-VM-definition, as in, differences between .java and .class. Trivial example: At least until the nestmates concept, the notion of 'an inner class' simply does not exist at the class file level. There is simply no such thing. Instead, javac fakes it: It turns:
class Outer {
private static int foo() {
return 5;
}
class Inner {
void example() {
Outer.foo();
}
}
}
Into 2 seemingly unrelated classes, one named Outer, and one named Outer$Inner, literally like that. You can trivially observe this: Compile the above file and look at that - 2 class files, not one.
This leaves one problem: The JLS claims that inner classes get to call private members from their outer class. However, at the JVMS (class file) level, we turned these 2 classes into separate things, and thus, Outer$Inner cannot call foo. Now what? Well, javac generates a 'bridger' method. It basically compiles this instead:
class Outer {
private static int foo() {
return 5;
}
/* synthetic */ static int foo$() {
return foo();
}
}
class Outer$Inner {
private /* synthetic */ Outer enclosingInstance;
void example() {
Outer.foo$();
}
}
The JVM can generate fields, extra overload methods (for example, if you write class MyClass implements List<String> {}, you will write e.g. add(String x), but .add(Object x) still needs to exist to cater to erasure - that method is generated by javac, and will be marked with the SYNTHETIC modifier.
One effect of the SYNTHETIC modifier is that javac acts as if these methods do not exist. If you attempt to actually write Outer.foo$() in java code, it won't compile, javac will act as if the method does not exist. Even though it does. If you use bytebuddy or a hex editor to clear that flag in the class file, then javac will compile that code just fine.
generating parameter names
Weirdly, perhaps, in the original v1.0 Java Language Spec, parameter types were, obviously, a required part of a method's signature and are naturally encoded in class files. You can write this code: Integer.class.getMethods();, loop through until you find the static parseInt method, and then ask the j.l.r.Method instance about its parameter type, which will dutifully report: the first param's type is String. You can even ask it for its annotations.
But weirdly enough as per JLS 1.0 you cannot ask for its name - simply because it is not there, there was no actual need to know it, it does take up space, java wanted to be installed on tiny devices (I'm just guessing at the reasons here), so the info is not there. You can add it - as debug info, via the -g parameter, because having the names of things is convenient.
However, in later days this was deemed too annoying, and more recently compilers DO stuff the param name in a class file. Even if you do not use the -g param to 'include debug symbol info'.
Which leaves one final question: java17 can still load classes produced by javac 1.1. So what is it supposed to do when you ask for the name of param1 of such a method? The name simply cannot be figured out, it simply isn't there in the class file. It can fall back to looking at the debug symbol table (and it does), but if that isn't there - then you're just out of luck.
What the JVM does is make that name arg0, arg1, etc. You may have seen this in decompiler outputs.
THAT is what the hasRealParameterData() method is referring to as 'real' - arg0 is 'synthesized', and in contrast, foo (the actual name of the param) is 'real'.
So how would one have a method that has 'real' data in that sense (the 4th bullet)? Simply compile it, it's quite hard to convince a modern java compiler to strip all param names. Some obfuscators do this. You can compile with a really old -target and definitely don't add -g, and you'll probably get non-real, as per hasRealParameterData().

Why java annotation syntax has () [parentheses]?

Why in "java" when you declare a "parameter" of an "annotation" you have to put "pair of parentheses" after the parameter, annotation are anyway "very different" form "interface" syntactically, so why this weird syntax...I know it has something to do with, that annotation are managed using interface behind the scenes or something, but what exactly?
This is what a normal interface declaration would look like:
public interface Example {
String method();
}
Note that when annotations were released, the java feature 'default methods for interfaces' wasn't around yet. The default keyword already existed (and has existed since java 1.0), solely as a thing you can put in a switch block, as the 'case' for 'it didnt match any of the cases'.
This is what an annotation interface definition looks like:
public #interface Example {
String method();
}
or, if defaults are involved:
public #interface Example {
String method() default "";
}
Note how parsing wise there is no difference between these two, other than the '#' symbol. In the 'default' case; yeah that's entirely new, but looking solely at that bit, it's not weird looking. The parentheses are, but not that bit.
The reason it's done this way is to not 'explode' parsing. Since the introduction of module-info in java9, if you want to write a parser for java, you mostly DO need an 'on the fly switching modes' parser; the "language specification" for a module file is so very different.
But that is a big step; the vast majority of parser libraries out there don't deal with this well, they can't switch grammars in the middle of parsing a source file.
Even if I can snap my fingers and break java (which, to be clear, java does not generally do: updating the language so that existing code now no longer compiles or means something else is a big step that is very rarely taken for obvious reasons. It restricts language design, though. That's the cost of being the world's most popular language*)... there are advantages here.
The way annotations work is that, if you at runtime obtain one, it acts like an object that is an instance of the annotation interface:
Example foo = Class.forName("foo.bar.Baz").getAnnotation(Example.class);
System.out.println(foo.method());
Note how it's not foo.method. It's foo.method(). And that has different reasons: fields, in java, are second-rate citizens. You can't put them in lambda method references (ClassName::methodName is valid java; there's no such thing for fields), they don't inherit, you can't put them in interfaces (fields in interfaces are automatically public, final, and static, i.e. constants. They don't decree a requirement to any implementing class, unlike methods in interfaces). That means fields as a general point of principle aren't used in public APIs in java. It'd be weird if in this instance they would be.
So, given that the params act like args-less method calls, it's convenient in that sense that you declare them that way as well in an #interface definition.
*) Give or take a few spots.

When are dot operators required?

When calling a method, I get that you have to use instanceName.method() or className.method(). However, in some cases the instanceName or className is omitted in the code and just method() is written.
Programming language is Java. Just covering this for the AP Computer Science test and I have relatively limited knowledge of coding outside of the parameters of the course so a easy to understand explanation would be greatly appreciated.
My book says something about client programs but I'm not exactly sure what it means (both in general and about client programs specifically).
I'll put my explanation as simply as possible - Usually you would use instanceName.method() when trying to effect the variables within a class. For example a "Cat" object, you could make a cat - Cat catOne = new Cat() and then use its methods catOne.setName("Kitty");. This will set this objects name to "Kitty", leaving all other cat objects with the ability to have their own unique name.
Using className.method() is done when using a static method within a class, eg public static int method(), and then using it in another class. This does not require you to instantiate an object for that class, and can use them willingly. For example, having a class called MathConstants and using something like MathConstants.getPi() ( Sorry for the crude example ).
When methods are called like methodName() , this means that the method is located within the class itself. Usually we use this , as in this.methodName(), but just using methodName() is okay.
Hope that is easy to understand

why MyClass.class exists in java and MyField.field isn't?

Let's say I have:
class A {
Integer b;
void c() {}
}
Why does Java have this syntax: A.class, and doesn't have a syntax like this: b.field, c.method?
Is there any use that is so common for class literals?
The A.class syntax looks like a field access, but in fact it is a result of a special syntax rule in a context where normal field access is simply not allowed; i.e. where A is a class name.
Here is what the grammar in the JLS says:
Primary:
ParExpression
NonWildcardTypeArguments (
ExplicitGenericInvocationSuffix | this Arguments)
this [Arguments]
super SuperSuffix
Literal
new Creator
Identifier { . Identifier }[ IdentifierSuffix]
BasicType {[]} .class
void.class
Note that there is no equivalent syntax for field or method.
(Aside: The grammar allows b.field, but the JLS states that b.field means the contents of a field named "field" ... and it is a compilation error if no such field exists. Ditto for c.method, with the addition that a field c must exist. So neither of these constructs mean what you want them to mean ... )
Why does this limitation exist? Well, I guess because the Java language designers did not see the need to clutter up the language syntax / semantics to support convenient access to the Field and Method objects. (See * below for some of the problems of changing Java to allow what you want.)
Java reflection is not designed to be easy to use. In Java, it is best practice use static typing where possible. It is more efficient, and less fragile. Limit your use of reflection to the few cases where static typing simply won't work.
This may irk you if you are used to programming to a language where everything is dynamic. But you are better off not fighting it.
Is there any use that is so common for class literals?
I guess, the main reason they supported this for classes is that it avoids programs calling Class.forName("some horrible string") each time you need to do something reflectively. You could call it a compromise / small concession to usability for reflection.
I guess the other reason is that the <type>.class syntax didn't break anything, because class was already a keyword. (IIRC, the syntax was added in Java 1.1.)
* If the language designers tried to retrofit support for this kind of thing there would be all sorts of problems:
The changes would introduce ambiguities into the language, making compilation and other parser-dependent tasks harder.
The changes would undoubtedly break existing code, whether or not method and field were turned into keywords.
You cannot treat b.field as an implicit object attribute, because it doesn't apply to objects. Rather b.field would need to apply to field / attribute identifiers. But unless we make field a reserved word, we have the anomalous situation that you can create a field called field but you cannot refer to it in Java sourcecode.
For c.method, there is the problem that there can be multiple visible methods called c. A second issue that if there is a field called c and a method called c, then c.method could be a reference to an field called method on the object referred to by the c field.
I take it you want this info for logging and such. It is most unfortunate that such information is not available although the compiler has full access to such information.
One with a little creativity you can get the information using reflection. I can't provide any examples for asthere are little requirements to follow and I'm not in the mood to completely waste my time :)
I'm not sure if I fully understand your question. You are being unclear in what you mean by A.class syntax. You can use the reflections API to get the class from a given object by:
A a = new A()
Class c = a.getClass()
or
Class c = A.class;
Then do some things using c.
The reflections API is mostly used for debugging tools, since Java has support for polymorphism, you can always know the actual Class of an object at runtime, so the reflections API was developed to help debug problems (sub-class given, when super-class behavior is expected, etc.).
The reason there is no b.field or c.method, is because they have no meaning and no functional purpose in Java. You cannot create a reference to a method, and a field cannot change its type at runtime, these things are set at compile-time. Java is a very rigid language, without much in the way of runtime-flexibility (unless you use dynamic class loading, but even then you need some information on the loaded objects). If you have come from a flexible language like Ruby or Javascript, then you might find Java a little controlling for your tastes.
However, having the compiler help you figure our potential problems in your code is very helpful.
In java, Not everything is an object.
You can have
A a = new A()
Class cls = a.getClass()
or directly from the class
A.class
With this you get the object for the class.
With reflection you can get methods and fields but this gets complicated. Since not everything is an object. This is not a language like Scala or Ruby where everything is an object.
Reflection tutorial : http://download.oracle.com/javase/tutorial/reflect/index.html
BTW: You did not specify the public/private/protected , so by default your things are declared package private. This is package level protected access http://download.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

trying to use only one method name

When I was programming a Form Validator in PHP, when creating new methods, I needed to increase the number of arguments in old methods.
When I was learning Java, when I read that extends is to not touch previously tested, working code, I thought I shouldn't have increased the number of arguments in the old methods, but overridden the old methods with the new methods.
Imagine if you are to verify if a field is empty in one part of the form, in an other and in yet an other.
If the arguments are different, you'll overload isEmpty, but, if the arguments are equal, is it right to use isEmpty, isEmpty2, isEmpty3, three classes and one isEmpty per class or, if both are wrong, what should I have done?
So the question is:
If I need different behaviors for a method isEmpty which receives the same number arguments, what should I do?
Use different names? ( isEmpty, isEmpty2, isEmpty3 )
Have three classes with a single isEmpty method?
Other?
If that's the question then I think you should use:
When they belong to the same logical unit ( they are of the same sort of validation ) but don't use numbers as version, better is to name them after what they do: isEmptyUser, isEmptyAddress, isEmptyWhatever
When the validator object could be computed in one place and passed around during the program lifecycle. Let's say: Validator v = Validator.getInstance( ... ); and then use it as : validator.isEmpty() and let polymorphism to it's job.
Alternatively you could pack the arguments in one class and pass it to the isEmpty method, although you'll end up with pretty much the same problem of the name. Still it's easier to refactor from there and have the new class doing the validation for you.
isEmpty( new Arguments(a,b,c ) ); => arguments.isEmpty();
The Open/Closed Principle [usually attributed to Bertrand Meyer] says that "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification". This might be the principle that you came across in your Java days. In real life this applies to completed code where the cost of modification, re-testing and re-certification outweighs the benefit of the simplicity gained by making a direct change.
If you are changing a method because it needs an additional argument, you might choose to use the following steps:
Copy the old method.
Remove the implementation from the copy.
Change the signature of the original method to add the new argument.
Update the implementation of the original method to use the new argument.
Implement the copy in terms of the new method with a default value for the argument.
If your implementation language doesn't support method overloading then the principle is the same but you need to find a new name for the new method signature.
The advantage of this approach is that you have added the new argument to the method, and your existing client code will continue to compile and run.
This works well if there is an obvious default for the new argument, and less well if there isn't.
Since java 5 you can use variable list of arguments as in void foo(Object ... params)
You will need to come up with creative names for your methods since you can't overload methods that have same type and number of arguments (or based on return type). I actually personally prefer this to overloading anyway. So you can have isEmpty and isEmptyWhenFoo and isEmptyWhenIHaveTheseArguments (well meybe not the last one :)
Not sure if this actually answers your question, but the best way to think about OO in "real life" is to think of the Nygaard Classification:
ObjectOrientedProgramming. A program execution is regarded as a physical model, simulating the behavior of either a real or imaginary part of the world.
So how would you build a physical device to do what you are trying to do in code? You'd probably have some kind of "Form" object, and the form object would have little tabs or bits connected to it to represent the different Form variables, and then you would build a Validator object that would take the Form object in a slot and then flash one light if the form was valid and another if it was invalid. Or your Validator could take a Form object in one slot and return a Form object out (possibly the same one), but modified in various ways (that only the Validator understood) to make it "valid". Or maybe a Validator is part of a Form, and so the Form has this Validator thingy sticking out of it...
My point is, try to imagine what such a machine would look like and how it would work. Then think of all of the parts of that machine, and make each one an object. That's how "object-oriented" things work in "real life", right?
With that said, what is meant by "extending" a class? Well, a class is a "template" for objects -- each object instance is made by building it from a class. A subclass is simply a class that "inherits" from a parent class. In Java at least, there are two kinds of inheritance: interface inheritance and implementation inheritance. In Java, you are allowed to inherit implementation (actual method code) from at most one class at a time, but you can inherit many interfaces -- which are basically just collections of attributes that someone can see from outside your class.
Additionally, a common way of thinking about OO programming is to think about "messages" instead of "method calls" (in fact, this is the original term invented by Alan Kay for Smalltalk, which was the first language to actually be called "object-oriented"). So when you send an isEmpty message to the object, how do you want it to respond? Do you want to be able to send different arguments with the isEmpty message and have it respond differently? Or do you want to send the isEmpty message to different objects and have them respond differently? Either are appropriate answers, depending on the design of your code.
Instead having one class providing multiple versions of isEmpty with differing names, try breaking down your model into a finer grained pieces the could be put together in more flexible ways.
Create an interface called Empty with
one method isEmpty(String value);
Create implemntations of this
interface like EmptyIgnoreWhiteSpace
and EmptyIgnoreZero
Create FormField
class that have validation methods
which delegate to implementations of
Empty.
Your Form object will have
instances of FormField which will
know how to validate themselves.
Now you have a lot of flexibility, you can combine your Empty implemenation classes to make new classes like EmptyIgnoreWhiteSpaceAndZero. You can use them in other places that have nothing to do with form field validation.
You don't have have have multple similarly named methods polluting your object model.

Categories

Resources