Where is the implementation of that function?
is a macro function
I searched the source code but couldn't find it
GTK_IS_ROOT() is defined by the G_DECLARE_INTERFACE (GtkRoot, gtk_root, GTK, ROOT, GtkWidget) at https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtkroot.h#L35 macro. This is a GObject macro and GTK uses GObject extensively.
Basically: when writing GObject classes or interfaces, you need to write quite a bit of boilerplace to implement inheritance right, ideally in a way that helps with ABI stability. GObject provides macros that make it easier for you: G_DECLARE_FINAL_TYPE(), G_DECLARE_DERIVABLE_TYPE() and G_DECLARE_INTERFACE() are macros that respectively do the declaration for a final class (which can't be subclassed), a derivable class, and an interface.
One of the things that you often want to do with runtime inheritance, is to perform certain checks related to the type of a certain parameter or variable. The aforementioned macros help out with that by generating some extra macros to implement such functionality.
Given a namespace Xxx (for example Gtk) and a type name Yyy (for example Root) it will provide an XXX_IS_YYY(var) macro to check if the given variable var is truly an instance of the class (i.e. it implements the instanceof() operator you might know of other languages)
Related
I am pondering over a few different ways of writing utility classes/functions. By utility I mean a part of code being reused in many places in the project. For example a set of formatting functions for the date & time handling.
I've got Java background, where there was a tendency to write
class UtilsXyz {
public static doSth(){...};
public static doSthElse(){...};
}
which I find hard to unit test because of their static nature. The other way is to inject here and there utility classes without static members.
In Dart you can use both attitudes, but I find other techniques more idiomatic:
mixins
Widely used and recommended in many articles for utility functions. But I find their nature to be a solution to infamous diamond problem rather than utility classes. And they're not very readable. Although I can imagine more focused utility functions, which pertain only Widgets, or only Presenters, only UseCases etc. They seem to be natural then.
extension functions
It's somehow natural to write '2023-01-29'.formatNicely(), but I'd like to be able to mock utility function, and you cannot mock extension functions.
global functions
Last not least, so far I find them the most natural (in terms of idiomatic Dart) way of providing utilities. I can unit test them, they're widely accessible, and doesn't look weird like mixins. I can also import them with as keyword to give some input for a reader where currently used function actually come from.
Does anybody have some experience with the best practices for utilities and is willing to share them? Am I missing something?
To write utility functions in an idiomatic way for Dart, your options are either extension methods or global functions.
You can see that they have a linter rule quoting this problem:
AVOID defining a class that contains only static members.
Creating classes with the sole purpose of providing utility or otherwise static methods is discouraged. Dart allows functions to exist outside of classes for this very reason.
https://dart-lang.github.io/linter/lints/avoid_classes_with_only_static_members.html.
Extension methods.
but I'd like to unit test some utility functions, and you cannot test extension functions, because they're static.
I did not find any resource that points that the extension methods are static, neither in StackOverflow or the Dart extension documentation. Although extension can have static methods themselves. Also, there is an open issue about supporting static extension members.
So, I think extensions are testable as well.
To test extension methods you have 2 options:
Import the extension name and use the extension syntax inside the tests.
Write an equivalent global utility function test it instead and make the extension method call this global function (I do not recommend this because if someone changes the extension method, the test will not be able to caught).
EDIT: as jamesdlin mentioned, the extension themselves can be tested but they cannot be mocked since they need to be resolved in compile time.
Global functions.
To test global functions, just import and test it.
I think the global functions are pretty straightforward:
This is the most simple, idiomatic way to write utility functions, this does not trigger any "wtf" flag when someone reads your code (like mixins), even Dart beginners.
This also takes advantage of the Dart top-level functions feature.
That's why I prefer this approach for utility functions that are not attached to any other classes.
And, if you are writing a library/package, the annotation #visibleForTesting may fall helpful for you (This annotation is from https://pub.dev/packages/meta).
I wonder if macros only have pros in any programming language. As there must be the limit we can create macros, and in frequency of use.
Suppose we create 100 macros in a class and imported that in 100 class of an application project. Is this a right approach?
#define is useful for:
header include guards for C and C++ headers (idiom: #include C and C++ headers, #import ObjC headers)
conditional compilation for language compatibility (e.g. UIKIT_EXTERN) which must be resolved during preprocessing.
conditional compilation for platform/compiler/version specific declarations (e.g. NS_AVAILABLE_IOS()) which must be resolved during preprocessing.
Assertion macros. Specifying the information such as the file, line and expression is just too noisy and error-prone.
for everything else, there is an alternative which will save you headaches along the way.
Suppose we create 100 macros in a class and imported that in 100 class of an application project. Is this a right approach?
no - that is terrifying :)
Cons
There are many. Too often, the program will be difficult to understand by humans and programs (compiler, parser, indexer) alike. It's a good way to introduce bugs, and completely replace text of unrelated programs (via a simple #import). There are more modern replacements for pretty much everything (e.g. functions, inline, typedef, constants, enums) -- Allow the compiler to make your life easier!
#define is a preprocessor macro. You do not create macro in a class as the macro is textually expanded on use but it's definition is not part of the class even if you happen to lexically write it within the class.
Also you do not import a class in other classes, you import the class declaration header. Imports only happen once per compilation unit even if you specify them multiple times. Therefore you'd still have at most one declaration of each macro in each compilation unit, and since macros are preprocessor only it'll only be there during the early phases of compilation.
You are not saying exactly what you want to use the macros for, therefore it's hard to say if they are the best solution for you or if you have a better alternative. But I would not worry about their number. The standard header files define hundreds of macros.
I'm reading "Practical Common Lisp" and I wonder if Common Lisp supports Duck-Typing like e.g. Ruby?
In Ruby it's possible to call a method on an object regardless of the class as long as it implements a method with the name and argument list that the caller assumes.
What about CLOS? Is it possible to call methods on objects without considering their class simply by assuming that a generic function will cope with it. Perhaps duck-typing is not needed because CLOS doesn't follow a message passing philosophy and methods are not bound to classes.
Perhaps duck-typing is not needed because CLOS doesn't follow a message passing philosophy and methods are not bound to classes.
That is exactly the case. Every generic function can be dynamically specialized for a certain class. There can also be a default implementation. And since Lisp uses dynamic typing, every function can be called with arguments of any type, and for generic functions the dispatch decision, based on the type of argument, is taken at runtime.
Interface (or an abstract class with all the methods abstract) is a powerful weapon in a static-typed language such as C#, JAVA. It allows different derived types to be used in a uniformed way. Design patterns encourage us to use interface as much as possible.
However, in a dynamic-typed language, all objects are not checked for their type at compile time. They don't have to implement an interface to be used in a specific way. You just need to make sure that they have some methods (attributes) defined. This makes interface not necessary, or at least not as useful as it is in a static language.
Does a typical dynamic language (e.g. ruby) have interface? If it does, then what are the benefits of having it? If it doesn't, then are we losing many of the beautiful design patterns that require an interface?
Thanks.
I guess there is no single answer for all dynamic languages. In Python, for instance, there are no interfaces, but there is multiple inheritance. Using interface-like classes is still useful:
Interface-like classes can provide default implementation of methods;
Duck-typing is good, but to an extent; sometimes it is useful to be able to write isinstance(x, SomeType), especially when SomeType contains many methods.
Interfaces in dynamic languages are useful as documentation of APIs that can be checked automatically, e.g. by development tools or asserts at runtime.
As an example, zope.interface is the de-facto standard for interfaces in Python. Projects such as Zope and Twisted that expose huge APIs for consumption find it useful, but as far as I know it's not used much outside this type of projects.
In Ruby, which is a dynamically-typed language and only allows single inheritance, you can mimic an "interface" via mixins, rather than polluting the class with the methods of the "interface".
Mixins partially mimic multiple inheritance, allowing an object to "inherit" from multiple sources, but without the ambiguity and complexity of actually having multiple parents. There is only one true parent.
To implement an interface (in the abstract sense, not an actual interface type as in statically-typed languages) You define a module as if it were an interface in a static language. You then include it in the class. Voila! You've gathered the duck type into what is essentially an interface.
Very simplified example:
module Equippable
def weapon
"broadsword"
end
end
class Hero
include Equippable
def hero_method_1
end
def hero_method_2
end
end
class Mount
include Equippable
def mount_method_1
end
end
h = Hero.new
h.weapon # outputs "broadsword"
m = Mount.new
m.weapon # outputs "broadsword"
Equippable is the interface for Hero, Mount, and any other class or model that includes it.
(Obviously, the weapon will most likely be dynamically set by an initializer, which has been simplified away in this example.)
To my surprise as I am developing more interest towards dynamic languages like Ruby and Python. The claim is that they are 100% object oriented but as I read on several basic concepts like interfaces, method overloading, operator overloading are missing. Is it somehow in-built under the cover or do these languages just not need it? If the latter is true are, they 100% object oriented?
EDIT: Based on some answers I see that overloading is available in both Python and Ruby, is it the case in Ruby 1.8.6 and Python 2.5.2 ??
Dynamic languages use duck typing.
Any code can call methods on any object that support those methods, so the concept
of interfaces is extraneous.
Python does in fact support operator overloading(check - 3.3. Special method names) , as does Ruby.
Anyway, you seem to be focusing on aspects that are not essential to object oriented programming. The main focus is on concepts like encapsulation, inheritance, and polymorphism, which are 100% supported in Python and Ruby.
Thanks to late binding, they do not need it. In Java/C#, interfaces are used to declare that some class has certain methods and it is checked during compile time; in Python, whether a method exists is checked during runtime.
Method overloading in Python does work:
>>> class A:
... def foo(self):
... return "A"
...
>>> class B(A):
... def foo(self):
... return "B"
...
>>> B().foo()
'B'
Are they object-oriented? I'd say yes. It's more of an approach thing rather than if any concrete language has feature X or feature Y.
I can only speak for python, but there have been proposals for interfaces as well as home-written interface examples in the past.
However, the way python works with objects dynamically tends to reduce the need for (and the benefit of) interfaces to some extent.
With a dynamic language, your type binding happens at runtime - interfaces are mostly used for compile time constraints on objects - if this happens at runtime, it eliminates some of the need for interfaces.
name based polymorphism
"For those of you unfamiliar with Python, here's a quick intro to name-based polymorphism. Python objects have an internal dictionary that contains a string for every attribute and method. When you access an attribute or method in Python code, Python simply looks up the string in the dict. Therefore, if what you want is a class that works like a file, you don't need to inherit from file, you just create a class that has the file methods that are needed.
Python also defines a bunch of special methods that get called by the appropriate syntax. For example, a+b is equivalent to a.add(b). There are a few places in Python's internals where it directly manipulates built-in objects, but name-based polymorphism works as you expect about 98% of the time. "
Python does provide operator overloading, e.g. you can define a method __add__ if you want to overload +.
You typically don't need to provide method overloading, since you can pass arbitrary parameters into a single method. In many cases, that single method can have a single body that works for all kinds of objects in the same way. If you want to have different code for different parameter types, you can inspect the type, or double-dispatch.
Interfaces are mostly unnecessary because of duck typing, as rossfabricant points out. A few remaining cases are covered in Python by ABCs (abstract base classes) or Zope interfaces.