question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

consider ignoring inherited properties in StrMap implementations

See original GitHub issue

@gabejohnson in https://github.com/sanctuary-js/sanctuary/pull/435#discussion_r135419232:

I don’t know that we necessarily should match the semantics of S.concat as it works on objects in general. I think we may [inadvertently] cause confusion by not explicitly defining StrMap. In my opinion inherited properties should not be copied for a StrMap.

This is worth discussing. Here’s an example which is not completely contrived:

function DigitCounter() {}

DigitCounter.count = ($counter, s) => {
  for (let idx = 0; idx < s.length; idx += 1) {
    const c = s[idx];
    if (/\d/.test(c)) $counter[c] += 1;
  }
};

for (let n = 0; n <= 9; n += 1) {
  DigitCounter.prototype[n] = 0;
}

const $counter = new DigitCounter();
DigitCounter.count($counter, String(Math.PI));

$counter;
// => {'1': 2, '2': 1, '3': 3, '4': 1, '5': 3, '6': 1, '7': 1, '8': 1, '9': 3}

Z.map(x => x, $counter);
// => {'0': 0, '1': 2, '2': 1, '3': 3, '4': 1, '5': 3, '6': 1, '7': 1, '8': 1, '9': 3}

Note that mapping x => x over $counter “promotes” the inherited property to an own property. The question is whether the inherited property should be ignored.

I believe the current behaviour is not just defensible but preferable. My reasoning is as follows:

  1. We currently use for ... in which respects all enumerable properties (both own and inherited). It ignores non-enumerable properties such as toString and valueOf. It’s unlikely that people are affected one way or the other by our handling of enumerable inherited properties; I imagine that close to 100% of string maps are plain objects.

  2. Although obscure, the example above shows that respecting enumerable inherited properties can be useful. We should not disallow such code without good reason.

  3. Z.concat is one of the library’s foundational functions. Performing a hasOwnProperty check for each key would affect the performance of several other functions as well as of Z.concat itself.

I look forward to understanding your reasons for suggesting that all <del>enumerable</del> inherited properties should be ignored, @gabejohnson. You may change my mind. 😃

sanctuary-js/sanctuary-def#164 contains related discussion about what constitutes a record field.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

3reactions
davidchamberscommented, Sep 6, 2017

it would help developers by giving them a very clear idea of what a StrMap is, it is a very simple thing, a POJO that maps to whatever your as are

This is how we should describe string maps to people regardless of how we handle this edge case. My preference is to permit the rarely useful behaviour we’ve been discussing, but this doesn’t mean we need to advertise it. Every example of a string map in the documentation is currently an object literal, and I don’t see any reason for this to change.

The definition should be precise of course, but this could be followed by a less technical description:

A value of type StrMap a is an object whose type is 'Object' and whose enumerable properties are all members of type a. A string map is a plain JavaScript object, such as {foo: 1, bar: 2, baz: 3}, whose values are all members of some type (Number, in this case).

2reactions
davidchamberscommented, Sep 9, 2017

This issue has just become clearer in my mind. These properties should undoubtedly hold:

  • S.keys(S.concat(map, {})) = S.keys(map)
  • S.keys(S.concat({}, map)) = S.keys(map)

It’s not difficult to find a counterexample:

function Point() {}
Point.prototype.x = 0;
Point.prototype.y = 0;

var map = new Point();

S.keys(map);
// => []

S.keys(S.concat(map, {}));
// => ['x', 'y']

So, either S.keys needs to be updated to include enumerable inherited properties or Z.concat and S.concat need to be updated to ignore enumerable inherited properties. I far prefer the latter.

At some point during the next few days I will open a pull request for this breaking change to Z.concat.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Automapper: ignore property on inherited class - Stack Overflow
Ok I think I had a brainfart when I wrote this code. model2.Property is never going to be null because it's a getter...
Read more >
Ignoring unmapped source properties in inverse inheritance
Final regarding ignoring unmapped source properties and inverse inheritance. Consider the mapping: @InheritInverseConfiguration(name = "toModel") ...
Read more >
The pitfalls of using objects as maps in JavaScript - 2ality
Alas, it considers inherited enumerable properties. ... With that function, the inherited property toString is ignored:
Read more >
Mapping Inheritance - AutoMapper documentation
MapFrom()); Inherited Explicit Mapping; Ignore Property Mapping; Convention Mapping (Properties that are matched via convention).
Read more >
Inheritance in Jackson | Baeldung
This tutorial will demonstrate how to handle inclusion of subtype metadata and ignoring properties inherited from superclasses with Jackson.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found