Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support final attributes #35

Closed
MarcelGarus opened this issue Sep 5, 2019 · 6 comments
Closed

Support final attributes #35

MarcelGarus opened this issue Sep 5, 2019 · 6 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@MarcelGarus
Copy link
Contributor

In my app, I have some immutable data class, like the following:

@immutable
@HiveType()
class SampleClass {
  @HiveField(0)
  final String someAttribute;

  @HiveField(1)
  final String otherAttribute;

  SampleClass({
    @required this.someAttribute,
    @required this.otherAttribute,
  })  : assert(someAttribute != null),
        assert(otherAttribute != null);
}

However, Hive currently cannot generate valid code for final fields because it relies on setting the attributes after creating the object (as it doesn't know about the constructor).

Is there a way final attributes could possibly be supported in the future?

@MarcelGarus MarcelGarus added the enhancement New feature or request label Sep 5, 2019
@simc
Copy link
Member

simc commented Sep 5, 2019

Yes it is possible but as you said, Hive would need to understand the constructors.

I don't think this is a very hard thing to implement but the generator may need some changes. This is definitely a planned feature but I'm currently working on other features and bugfixes.

Another important thing that is missing are unit tests for the generator. I'm not sure how to do that ^^

I would appreciate your help if you want to to implement the constructor feature ;)

@simc simc added the help wanted Extra attention is needed label Sep 5, 2019
@MarcelGarus
Copy link
Contributor Author

Hmm, the more I think about this, the more complex this feature seems.

Like, theoretically, the classes can be complex, mixing final and non-final fields and altering them in the constructor.

For example, consider the following class:

@HiveType()
class Label {
  @HiveField(0)
  final String name;

  @HiveField(1)
  String author;

  Label();

  Label.withLowercaseName(String name) : this.name = name.toLowercase();

  Label.withName(this.name);
}

Theoretically, hive could be clever enough to come up with would be something of the likes:

return SampleClass.withName(name)
    ..author = author;

But that seems complex, especially considering that attributes can be named, positioned or required.
There's just a lot of variation going on in constructors.
So I'm afraid the code generator would become very complex.


Another option would be to limit the constructors that are accepted, maybe even requiring a fromHive constructor for classes that contain final fields, something like this:

@HiveType()
class Label {
  ...

  Label.fromHive({
    this.name,
    this.author
  });
}

Any ideas on how to proceed?
What do you think about requiring a special constructor for classes with final fields that still want to be stored in hive?

@MarcelGarus
Copy link
Contributor Author

Quick sidenote: For my use case I just created a package data_classes that can convert a mutable class from and to an immutable class pendant.
So you could define a mutable class in a few lines of code and annotate it with @HiveType. An immutable class gets generated that can be used everywhere else in the app. When you want to save such a class to hive, you can convert it to the mutable class and save this to hive. Vice versa for retrieving objects from hive.

@simc
Copy link
Member

simc commented Sep 6, 2019

I think it is not that complex to make it work with named and positioned parameters. The only thing I would require is that the constructor uses the this.myAttribute initialization.

A constructor may look like this:

class MyClass {
  String name;
  int age;

  MyClass(this.age, {this.name});

The data_classes package is really cool...

@MarcelGarus
Copy link
Contributor Author

Okay, so we use the unnamed constructor and set only those fields that are assigned with this.field.
Just to be sure, let's say we have a class

@HiveType()
class MyClass {
  @HiveField(0)
  final String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  int fieldThatIsNotInTheConstructor;

  MyClass(this.age, {this.name});
}

I'll try to implement the generator so that the generated code could then look like this:

MyClass read(BinaryReader reader) {
  var numOfFields = reader.readByte();
  var fields = <int, dynamic>{
    for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
  };
  return MyClass(
    fields[1] as int,
    name: fields[0] as String,
  )..fieldThatIsNotInTheConstructor = fields[2] as int;
}

@simc
Copy link
Member

simc commented Sep 6, 2019

Yes that looks good 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants