So I used to maintain configurations as dicts in the past and then stumbled over enums in python.
The following is what I used to do before:
CONFIG = {
"field1": {"field11": "value11", ....},
"field2": {"field12": "value22", .....},
}
This would be a global and would contain some configuration that my application would use.
I then converted the same using enums are follows:
from enum import Enum, unique
#unique
class Config(Enum):
field1 = {"field11": "value11", .....}
field2 = {"field22": "value22", .....}
The benefit of using enums was quite hazy at first but when I dug deep, I found out enums are immutable, one can enforce uniqueness and it offers a cleaner way to iterate across its members.
I checked if this was used in any of the python third party or standard libraries. I found out that majority of them were using a class as follows:
class Config:
field1 = {"field11": "value11", .....}
field2 = {"field22": "value22", .....}
So my question is, is enums a good choice to hold configs which shouldn't be accidentally changed or its just overkill and one can get away with using a class instead?
Would like to know which one is considered as the best practise.
The main advantage of using enum in your question is that it allows the writing of symbolic constants in the code, whereas using dictionary you'd have have to check the dictionary for the key, e.g:
Config.field1
versus
Config["field1"]
So the difference would be advantage in syntax, but also that enum is inherently immutable unlike dictionary, and also that enum can't be extended unlike class.
Related
I am using nu.studer.jooq gradle plugin to generate pojos, tables and records for a PostgreSQL database with tables that have fields of type ENUM.
We already have the enums in the application, so I would like that the generator uses those enums instead of generating new ones.
I defined in build.gradle for the generator: udts = false, so it doesn't generate the enums, and I wrote a custom generator strategy that sets the package for the enums to be the one of the already existing enums.
I have an issue in the generated table fields, the SQLDataType.VARCHAR.asEnumDataType(mypackage.ExistingEnum) doesn't work because the mypackage.ExistingEnum does not implement org.jooq.EnumType.
public enum ExistingEnum {
VAL1, VAL2
}
Generated table record:
public class EntryTable extends TableImpl<EntryRecord> {
public final TableField<EntryRecord, ExistingEnum> MY_FIELD = createField(DSL.name("my_field"), SQLDataType.VARCHAR.asEnumDataType(mypackage.ExistingEnum.class), this, "");
}
Is there something I can do to fix this issue? Also we have a lot of enums, so writing a converter for each of them is not suitable.
The point of having custom enum types is that they are individual types, independent of whatever you encode with your database enum types. As such, the jOOQ code generator cannot make any automated assumptions related to how to map the generated types to the custom types. You'll have to implement Converter types of some sort.
If you're not relying on the jOOQ provided EnumType types, you could use the <enumConverter/> configuration, or write implementations based on org.jooq.impl.EnumConverter, which help reduce boilerplate code.
If you have some conventions or rules how to map things a bit more automatically (just because jOOQ doesn't know your convention doesn't mean you don't know it either), you could implement a programmatic code generation configuration, where you query your dictionary views (e.g. PG_CATALOG.PG_ENUM) to generate ForcedType objects. You can even use jOOQ-meta for that purpose.
Say we have
class Foo {}
Is there a way to obtain "Foo" from within the class?
Yes.
class Foo {
say ::?CLASS.^name; # OUTPUT: Foo
}
Kaiepi's solution has its place, which I'll get to below, but also consider:
class Foo {
say Foo.perl; # Foo
say OUR.WHO; # Foo
::?PACKAGE
}
Foo.perl
This provides a simple answer to your literal question (though it ignores what you're really after, as explained in your comment below and as suggested by the metaprogramming tag and your use of the word "introspection").
OUR.WHO
I think this is typically more appropriate than ::?CLASS.^name for several reasons:
Looks less line-noisy.
Works for all forms of package, i.e. ones declared with the built in declarators package, module, grammar, or role as well as class, and also custom declarators like actor, monitor, etc.
Will lead readers to mostly directly pertinent issues if they investigate OUR and/or .WHO in contrast to mostly distracting arcana if they investigate the ::?... construct.
::?CLASS vs ::?PACKAGE
OUR.WHO only works in a value grammatical slot, not a type grammatical slot. For the latter you need a suitable ::?... form, eg:
class Foo { has ::?CLASS $bar }
And these ::?... forms also work as values:
class Foo { has $bar = ::?CLASS }
So, despite their relative ugliness, they're more general in this particular sense. That said, if generality is at a premium then ::?PACKAGE goes one better because it works for all forms of package.
I have a library of domain objects which need to be used in the project, however we've found a couple of the classes haven't got an equals or hashCode method implemented.
I'm looking for the simplest (and Grooviest) way to add those methods. Obviously I could create a subclass which only adds the methods, but this would be confusing for developers used to the library and would mean we'd have to refactor existing code.
It is not possible to get the source changed (currently).
If I could edit the class I would just use the #EqualsAndHashCode annotation to carry out an AST transformation (at compile time?), but I can't find a way to instruct the compiler to carry out the transformation on a class which I can't directly annotate.
I'm currently trying to work up an example using the ExpandoMetaClass, so I'd do something like:
MySuperClass.metaClass.hashCode = { ->
// Add dynamic hashCode calculation bits here
}
MySuperClass.metaClass.equals = { ->
// Add dynamic hashCode calculation bits here
}
I don't really want to hand-code the hashCode/equals methods for each class, so I'm looking for something dyamic (like #EqualsAndHashCode) which will work with this.
Am I on the right track? Is there a groovier way?
AST Transforms are only applied at compile time, so you'll get no help from the likes of #EqualsAndHashCode. MetaClass hacks are going to be your only option. That said, there are more-elegant ways to impose MetaClass behavior.
Shameless Self Plug I did a talk about this kind of stuff last year at SpringOne 2GX: http://www.infoq.com/presentations/groovy-app-architecture
In short, you might find benefit in creating extensions (unless you're in Grails) - http://mrhaki.blogspot.com/2013/01/groovy-goodness-adding-extra-methods.html, or by explicitly adding mixins - http://groovy.codehaus.org/Runtime+mixins ... But in general, these are just cleaner ways to do the exact same thing you're already doing.
I would like to be able to use plain java-style implicit/explicit casting instead of asType overrides so that sources written in Java work properly. I've overridden asType on String similarly to the approach suggested in How to overload some Groovy Type conversion for avoiding try/catch of NumberFormatException? like:
oldAsType = String.metaClass.getMetaMethod("asType", [Class] as Class[])
String.metaClass.asType = {Class typ ->
if (Foo.class.isAssignableFrom(typ)) {
Foo.myCast(delegate)
} else {
oldAsType.invoke(delegate,typ)
}
}
I'd like all of these options to work:
// groovy
String barString
Foo foo = barString asType(Foo.class) // asType works but
Foo foo = barString // implicit cast fails
Foo foo = (Foo) barString // explicit cast fails
The latter two fail because groovy is using DefaultTypeTransformation.castToType, which doesn't attempt to invoke new Foo() unless the object to be cast is either one of a slew of special cases or is some sort of Collection type.
Note that the solution Can I override cast operator in Groovy? doesn't solve the issue because the code that is doing the casting is regular Java code that I cannot alter, at least not at the source code level. I'm hoping that there is either a secret hook into casting or a way to override the static castToType method (in a Java class, called by another Java class - which Can you use Groovy meta programming to override a private method on a Java class says is unsupported)... or some other clever approach I haven't thought of.
Edit: The question is about using Java-style casting syntax, essentially to use groovy facilities to add an autoboxing method. Groovy calls this mechanism "casting," for better or worse (see DefaultTypeTransformation.castToType as referenced above). In particular, I have replaced an enum with a resourced class and want to retain JSON serialization. Groovy's JSON package automatically un/marshals enum values of instance members to strings and I'm trying to make the replacement class serialize compatibly with a minimal changes to the source code.
Part of the problem here is you are confusing conversion with casting. Using the "as" operator is not the same thing as imposing a cast. They seem similar, but they serve separate purposes.
Foo foo = (Foo) barString
That doesn't say something like "create a Foo out of barString". That says "Declare a reference named foo, associate the static type Foo with that reference and then point that reference at the object on the heap that the reference barString currently points to.". Unlike languages like C++, Groovy and Java do not allow you to ever get in a situation where a reference points at an object that is of a type that is incompatible with the reference's type. If you ever got into a situation where a Foo reference was pointing to a String on the heap, that would represent a bug in the JVM. It cannot be done. You can come up with ways to create Foo objects out of String objects, but that isn't what the code above is about.
The answer appears to be "no". Absent a rewrite of the DefaultTypeTransformation.castToType to allow for this sort of metaprogramming, the implication is to use another implementation strategy or use a different language.
I am trying to save an Object which implements an Interface say IInterface.
private PersistentDictionary<string, IInterface> Object = new PersistentDictionary<string, IInterface>(Environment.CurrentDirectory + #"\Object");
Since many classes implement the same interface(all of which need to cached), for a generic approach I want to store an Object of type IInterface in the dictionary.
So that anywhere I can pull out that object type cast it as IInterface and use that object's internal implementation of methods etc..
But, as soon as the Esent cache is initialized it throws this error:
Not supported for SetColumn
Parameter name: TColumn
Actual value was IInterface.
I have tried to not use XmlSerializer to do the same but is unable to deserialize an Interface type.Also, [Serializable] attribute cannot be used on top of a Interface, so I am stuck.
I have also tried to make all the implementations(classes) of the Interface as [Serializable] as a dying attempt but to no use.
Does any one know a way out ? Thanks in advance !!!
The only reason that only structs are supported (as well as some basic immutable classes such as string) is that the PersistentDictionary is meant to be a drop-in replacement for Dictionary, SortedDictionary and other similar classes.
Suppose I have the following code:
class MyClass
{
int val;
}
.
.
.
var dict = new Dictionary<int,MyClass>();
var x = new MyClass();
x.val = 1;
dict.Add(0,x);
x.val = 2;
var y = dict[0];
Console.WriteLine(y.val);
The output in this case would be 2. But if I'd used the PersistentDictionary instead of the regular one, the output would be 1. The class was created with value 1, and then changed after it was added to the dictionary. Since a class is a reference type, when we retrieve the item from the dictionary, we will also have the changed data.
Since the PersistentDictionary writes the data to disk, it cannot really handle reference types this way. Serializing it, and writing it to disk is essentially the same as treating the object as a value type (an entire copy is made).
Because it's intended to be used instead of the standard dictionaries, and the fact that it cannot handle reference types with complete transparency, the developers instead opted to support only structs, because structs are value types already.
However, if you're aware of this limitation and promise to be careful not to fall into this trap, you can allow it to serialize classes quite easily. Just download the source code and compile your own version of the EsentCollections library. The only change you need to make to it is to change this line:
if (!(type.IsValueType && type.IsSerializable))
to this:
if (!type.IsSerializable)
This will allow classes to be written to the PersistentDictionary as well, provided that it's Serializable, and its members are Serializable as well. A huge benefit is that it will also allow you to store arrays in there this way. All you have to keep in mind is that it's not a real dictionary, therefore when you write an object to it, it will store a copy of the object. Therefore, updating any of your object's members after adding them to the PersistentDictionary will not update the copy in the dictionary automatically as well, you'd need to remember to update it manually.
PersistentDictionary can only store value-structs and a very limited subset of classes (string, Uri, IPAddress). Take a look at ColumnConverter.cs, at private static bool IsSerializable(Type type) for the full restrictions. You'd be hitting the typeinfo.IsValueType() restriction.
By the way, you can also try posting questions about PersistentDictionary at http://managedesent.codeplex.com/discussions .
-martin