Skip to content
This repository was archived by the owner on Oct 17, 2024. It is now read-only.

Added IdentityCodec #17

Merged
merged 3 commits into from
Dec 12, 2018
Merged

Added IdentityCodec #17

merged 3 commits into from
Dec 12, 2018

Conversation

jonasfj
Copy link
Contributor

@jonasfj jonasfj commented Dec 3, 2018

This is useful you're making a parameterized type that can be fused with a Codec to create a wrapper with different type parameters...

Example of when this could be useful to have:

T someFunction<S,T>(S value, [Codec<S,T> codec = const IdentityCodec()]) {
  ...
}

When implementing functions that accept an optional Codec a good default is IdentityCodec, if you expect users to use the function without the Codec.

@jonasfj
Copy link
Contributor Author

jonasfj commented Dec 3, 2018

Note: this is also useful as default value for functions/methods that takes a Codec as a optional parameter.

@kevmoo
Copy link
Contributor

kevmoo commented Dec 3, 2018

Should add a changelog entry and maybe bump the version?

CC @lrhn

@lrhn
Copy link
Contributor

lrhn commented Dec 3, 2018

I would definitely put this in package:collection, not the platform libraries.
So, yes, add to changelog and update minor version.

@jonasfj
Copy link
Contributor Author

jonasfj commented Dec 3, 2018

@lrhn, sorry the example at top was a bit confusing, this is an identity Codec<T,T> it has nothing to do with caching... Other that it's useful when implementing a cache :)

I updated the PR description. And updated changelog + bumped version.

Copy link
Contributor

@lrhn lrhn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need (some smallish) testing.

const IdentityCodec();

@override
Converter<T, T> get decoder => _IdentityConverter();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to be explicit instead of depending on inference, so consider _IdentityConverter<T>() here and below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making it a field:

final Converter<T, T> decoder = _IdentityConverter<T>();
Converter<T, T> get encoder => decoder;

Then you only create one converter per codec. It costs more if you end up not using the codec, but otherwise it should be a wash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat trick..

To be fair I was hoping the JIT would just optimize it out...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So...

final Converter<T, T> decoder = const _IdentityConverter<T>();
Converter<T, T> get encoder => decoder;

Won't work because:

[dart] A constant creation can't use a type parameter as a type argument. [const_with_type_parameters]

It also fails in test.

We should want IdentityCodec to have a const constructor, so that it can be used as default value for optional parameters.


If we really want to optimize things we could do:

// global identity converter, so we only create one instance
final _identityConverter = const _IdentityConverter<dynamic>();

class IdentityCodec<T> extends Codec<T, T> {
  const IdentityCodec();
  Converter<T, T> get decoder => _identityConverter.cast();
  Converter<T, T> get encoder => _identityConverter.cast();
  Codec<T, R> fuse<R>(Codec<T, R> other) => other;
}

But I'm not quite sure of the wisdom of using dynamic, vs. hoping the optimizer will trace away the useless _IdentityConverter instances created with:

  Converter<T, T> get decoder => _IdentityConverter<T>();
  Converter<T, T> get encoder => _IdentityConverter<T>();

Maybe it's best to wait for a performance problem before we think ahead. Or we could argue that we should have language features that allows const type parameterization :)

///
/// This will return the [other] codec, as the identity codec is trivial.
@override
Codec<T, R> fuse<R>(Codec<T, R> other) => other;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not handling the case of other.fuse(identityCodec).

On the other hand, I don't want the generic fuse to know about IdentifyCodec (it could mean that the class is harder to tree-shake).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could document this behavior, but that seems overkill.. And cost of doing it wrong is likely small anyways.

@jonasfj
Copy link
Contributor Author

jonasfj commented Dec 12, 2018

@lrhn, if by chance you have time to accept/reject this that would be great.
I have no problem publishing it as a separate package.. Or embedding where I need it :)

@lrhn lrhn merged commit 0310659 into dart-archive:master Dec 12, 2018
@lrhn
Copy link
Contributor

lrhn commented Dec 12, 2018

Thanks. I've merged it and will publish a new version.

aaronlademann-wf added a commit to aaronlademann-wf/convert that referenced this pull request Dec 19, 2018
+ Fixes DDC compilation regression introduced by dart-archive#17
kevmoo pushed a commit that referenced this pull request Dec 19, 2018
Fixes DDC compilation regression introduced by #17
mosuem pushed a commit to dart-lang/core that referenced this pull request Oct 15, 2024
mosuem pushed a commit to dart-lang/core that referenced this pull request Oct 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging this pull request may close these issues.

4 participants