Recommended/Canonical format for POM functions - playwright

This is more of a style question. When using the POM for Playwright, I've seen 2 different ways of defining classes for export. Was wondering if one is better than the other, or makes any difference in functionality/speed.
So in a POM file, lets call it pomfunctions.js
First way:
exports.PlaywrightDevPage = class PlaywrightDevPage {
constructor section
functions defined here:
}
OR this way:
class PlaywrightDevPage {
constructor section
functions defined here
}
module.exports = { PlaywrightDevPage };

Both are equivalent, since exports points to the same object as module.exports (you just can’t reassign a whole object to export, just its properties - see the Node docs on the exports shortcut) and the module.exports form is using property shorthand syntax (see MDN doc on property definition).
So it really is mostly just a preference, and these Q&A aren’t meant for opinions, so I’ll just say from personal experience that I have more commonly (if not only) seen the module.exports version (so feels like a convention but have no other backing to that), at least for these CommonJS forms, and refrain from stating my opinion on why I like it more as well. I don’t know if there’s a standard though, so believe it’s just up to you!
Hope that helps!

Related

Why is using final, with no type, considered good practice in Dart? ie `final foo = config.foo;`?

I see this recommended in the dart style guide, and copied in tons of tutorials and flutter source.
final foo = config.foo;
I don't understand it, how is this considered best practice when the readability is so poor? I have no clue what foo is here, surely final String foo = config.foo is preferable if we really want to use final?
This seems the equivalent to using var, which many consider a bad practice because it prevents the compiler from spotting errors and is less readable.
Where am I wrong?
In a lot of cases is does not really matter what type you are using as long the specific type can be statically determined by the compiler. When you are using var/final in Dart it is not that Dart does not know the type, it will just figure it out automatically based on the context. But the type must still be defined when the program are compiled so the types will never be dynamic based on runtime behavior. If you want truly dynamic types, you can use the dynamic keyword where you tell Dart "trust me, I know what I am doing with this types".
So types should still be defined where it matter most. This is e.g. for return and argument types for methods and class variables. The common factor for this types is that they are used to define the interface for using the method or class.
But when you are writing code inside a method, you are often not that interested in the specific types of variables used inside the method. Instead the focus should be the logic itself and you can often make it even more clear by using good describing variable names. As long the Dart analyzer can figure out the type, you will get autocomplete from your IDE and you can even still see the specific type from your IDE by e.g. Ctrl+Q in IntelliJ on the variable if you ends up in a situation where you want to know the type.
This is in particular the case when we are talking about the use of generics where it can be really tiresome to write the full specific type. Especially if you are using multiple generics inside each other like e.g. Map<String, List<String>>.
In my experience, Dart is really good to figure out very specific types and will complain loudly if your code cannot be determined statically. In the coming future, Dart will introduce non-null by default, which will make the Dart compiler and analyzer even more powerful since it will make sure your variable cannot be null unless this is something you specifically want and will make sure you are going to test for null when using methods which are specified to not expecting null.
About "Where am I wrong?". Well, a lot of languages have similar feature of var/final like Dart with the same design principle about the type should still be statically determined by a compiler or runtime. And even Java has introducing this feature. As a experienced Java and Dart programmer I have come to the conclusion for myself that typing inside methods are really not that important in a lot of cases as long I can still easily figure out the specific type by using an IDE when it really matters.
But it does make it more important to name your variables so they are clearly defining the purpose. But I am hoping you already are doing that. :)

Improving apostrophe-pieces

I want to create a module that improves the existing apostrophe-pieces for the purpose of translate pieces.
So I make my module and I add a index.js file.
module.exports = {
improve: 'apostrophe-pieces',
alias:'apostrophe-translated-pieces',
construct: function(self, options) {
self.afterList = function(req, results, callback) {
console.log('my function');
return callback();
};
}
};
But the initial function is always called, and not mine. What is wrong with my approach?
There are two issues. First, it does not make sense to combine alias with improve. The purpose of improve is to implicitly subclass apostrophe-pieces so that all modules derived from apostrophe-pieces get your changes. The purpose of alias is to give a module a new name and that is not what you are trying to do.
Second, improve is really intended for npm modules, and does not currently work in "project level" code. You don't specify here but I assume you're doing this at project level, in lib/modules/apostrophe-translated-pieces.
So how do you do this at project level? It's actually even simpler: you just create lib/modules/apostrophe-pieces/index.js in your project and put your code there. If you supply an implementation for a module that is part of Apostrophe core, it is automatically loaded as an implicit subclass, doing exactly what you are hoping. You don't need the improve keyword for that (or alias for that matter).
The purpose of improve is to let you pull off the same trick in an npm module you will publish and share with others, even though it can't (or shouldn't) have the same name as one of our modules. That issue doesn't come up at project level.
Finally... you should check out the apostrophe-workflow module. The new 2.x version of apostrophe-workflow also covers localization/translation and it does so very thoroughly. So it might not make sense to write your own implementation of translation, depending on your needs.

Using Dart as a DSL

I am trying to use Dart to tersely define entities in an application, following the idiom of code = configuration. Since I will be defining many entities, I'd like to keep the code as trim and concise and readable as possible.
In an effort to keep boilerplate as close to 0 lines as possible, I recently wrote some code like this:
// man.dart
part of entity_component_framework;
var _man = entity('man', (entityBuilder) {
entityBuilder.add([TopHat, CrookedTeeth]);
})
// test.dart
part of entity_component_framework;
var man = EntityBuilder.entities['man']; // null, since _man wasn't ever accessed.
The entity method associates the entityBuilder passed into the function with a name ('man' in this case). var _man exists because only variable assignments can be top-level in Dart. This seems to be the most concise way possible to use Dart as a DSL.
One thing I wasn't counting on, though, is lazy initialization. If I never access _man -- and I had no intention to, since the entity function neatly stored all the relevant information I required in another data structure -- then the entity function is never run. This is a feature, not a bug.
So, what's the cleanest way of using Dart as a DSL given the lazy initialization restriction?
So, as you point out, it's a feature that Dart doesn't run any code until it's told to. So if you want something to happen, you need to do it in code that runs. Some possibilities
Put your calls to entity() inside the main() function. I assume you don't want to do that, and probably that you want people to be able to add more of these in additional files without modifying the originals.
If you're willing to incur the overhead of mirrors, which is probably not that much if they're confined to this library, use them to find all the top-level variables in that library and access them. Or define them as functions or getters. But I assume that you like the property that variables are automatically one-shot. You'd want to use a MirrorsUsed annotation.
A variation on that would be to use annotations to mark the things you want to be initialized. Though this is similar in that you'd have to iterate over the annotated things, which I think would also require mirrors.

Do Delphi generic collections override equals?

This is a question for the generic collection gurus.
I'm shocked to find that TList does not override equals. Take a look at this example:
list1:=TList<String>.Create;
list2:=TList<String>.Create;
list1.Add('Test');
list2.Add('Test');
Result:=list1.Equals(list2);
"Result" is false, even though the two Lists contain the same data. It is using the default equals() (which just compares the two references for equality).
Looking at the code, it looks like the same is true for all the other generic collection types too.
Is this right, or am I missing something??
It seems like a big problem if trying to use TLists in practice. How do I get around this? Do I create my own TBetterList that extends TList and overrides equals to do something useful?
Or will I run into further complications with Delphi generics...... ?
[edit: I have one answer so far, with a lot of upvotes, but it doesn't really tell me what I want to know. I'll try to rephrase the question]
In Java, I can do this:
List<Person> list1=new ArrayList<Person>();
List<Person> list2=new ArrayList<Person>();
list1.add(person1);
list2.add(person1);
boolean result=list1.equals(list2);
result will be true. I don't have to subclass anything, it just works.
How can I do the equivalent in Delphi?
If I write the same code in Delphi, result will end up false.
If there is a solution that only works with TObjects but not Strings or Integers then that would be very useful too.
Generics aren't directly relevant to the crux of this question: The choice of what constitutes a valid base implementation of an Equals() test is entirely arbitrary. The current implementation of TList.Equals() is at least consistent will (I think) all other similar base classes in the VCL, and by similar I don't just mean collection or generic classes.
For example, TPersistent.Equals() also does a simple reference comparison - it does not compare values of any published properties, which would arguably be the semantic equivalent of the type of equality test you have in mind for TList.
You talk about extending TBetterList and doing something useful in the derived class as if it is a burdensome obligation placed on you, but that is the very essence of Object Oriented software development.
The base classes in the core framework provide things that are by definition of general utility. What you consider to be a valid implementation for Equals() may differ significantly from someone else's needs (or indeed within your own projects from one class derived from that base class to another).
So yes, it is then up to you to implement an extension to the provided base class that will in turn provide a new base class that is useful to you specifically.
But this is not a problem.
It is an opportunity.
:)
You will assuredly run into further problems with generics however, and not just in Delphi. ;)
What it boils down to is this:
In Java (and .NET languages) all types descend from Object. In Delphi integers, strings, etc. do not descend from TObject. They are native types and have no class definition.
The implications of this difference are sometimes subtle. In the case of generic collections Java has the luxury of assuming that any type will have a Equals method. So writing the default implementation of Equals is a simple matter of iterating through both lists and calling the Equals method on each object.
From AbstractList definition in Java 6 Open JDK:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while(e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
As you can see the default implementation isn't really all that deep a comparison after all. You would still be overriding Equals for comparison of more complex objects.
In Delphi since the type of T cannot be guaranteed to be an object this default implementation of Equals just won't work. So Delphi's developers, having no alternative left overriding TObject.Equals to the application developer.
I looked around and found a solution in DeHL (an open source Delphi library). DeHL has a Collections library, with its own alternative List implementation. After asking the developer about this, the ability to compare generic TLists was added to the current unstable version of DeHL.
So this code will now give me the results I'm looking for (in Delphi):
list1:=TList<Person>.Create([Person.Create('Test')]);
list2:=TList<Person>.Create([Person.Create('Test')]);
PersonsEqual:=list1.Equals(list2); // equals true
It works for all types, including String and Integer types
stringList1:=TList<string>.Create(['Test']);
stringList2:=TList<string>.Create(['Test']);
StringsEqual:=stringList1.Equals(stringList2); // also equals true
Sweet!
You will need to check out the latest unstable version of DeHL (r497) to get this working. The current stable release (0.8.4) has the same behaviour as the standard Delphi TList.
Be warned, this is a recent change and may not make it into the final API of DeHL (I certainly hope it does).
So perhaps I will use DeHL instead of the standard Delphi collections? Which is a shame, as I prefer using standard platform libraries whenever I can. I will look further into DeHL.

F# mutual recursion between modules

For recursion in F#, existing documentation is clear about how to do it in the special case where it's just one function calling itself, or a group of physically adjacent functions calling each other.
But in the general case where a group of functions in different modules need to call each other, how do you do it?
I don't think there is a way to achieve this in F#. It is usually possible to structure the application in a way that doesn't require this, so perhaps if you described your scenario, you may get some useful comments.
Anyway, there are various ways to workaround the issue - you can declare a record or an interface to hold the functions that you need to export from the module. Interfaces allow you to export polymorphic functions too, so they are probably a better choice:
// Before the declaration of modules
type Module1Funcs =
abstract Foo : int -> int
type Module2Funcs =
abstract Bar : int -> int
The modules can then export a value that implements one of the interfaces and functions that require the other module can take it as an argument (or you can store it in a mutable value).
module Module1 =
// Import functions from Module2 (needs to be initialized before using!)
let mutable module2 = Unchecked.defaultof<Module2Funcs>
// Sample function that references Module2
let foo a = module2.Bar(a)
// Export functions of the module
let impl =
{ new Module1Funcs with
member x.Foo(a) = foo a }
// Somewhere in the main function
Module1.module2 <- Module2.impl
Module2.module1 <- Module1.impl
The initializationcould be also done automatically using Reflection, but that's a bit ugly, however if you really need it frequently, I could imagine developing some reusable library for this.
In many cases, this feels a bit ugly and restructuring the application to avoid recursive references is a better approach (in fact, I find recursive references between classes in object-oriented programming often quite confusing). However, if you really need something like this, then exporting functions using interfaces/records is probably the only option.
This is not supported. One evidence is that, in visual stuido, you need to order the project files correctly for F#.
It would be really rare to recursively call two functions in two different modules.
If this case does happen, you'd better factor the common part of the two functions out.
I don't think that there's any way for functions in different modules to directly refer to functions in other modules. Is there a reason that functions whose behavior is so tightly intertwined need to be in separate modules?
If you need to keep them separated, one possible workaround is to make your functions higher order so that they take a parameter representing the recursive call, so that you can manually "tie the knot" later.
If you were talking about C#, and methods in two different assemblies needed to mutually recursively call each other, I'd pull out the type signatures they both needed to know into a third, shared, assembly. I don't know however how well those concepts map to F#.
Definetely solution here would use module signatures. A signature file contains information about the public signatures of a set of F# program elements, such as types, namespaces, and modules.
For each F# code file, you can have a signature file, which is a file that has the same name as the code file but with the extension .fsi instead of .fs.

Resources