{"id":535,"date":"2017-05-17T01:18:46","date_gmt":"2017-05-16T17:18:46","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/seteplia\/?p=535"},"modified":"2019-06-11T22:39:22","modified_gmt":"2019-06-12T05:39:22","slug":"box-or-not-to-box-that-is-the-question","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/box-or-not-to-box-that-is-the-question\/","title":{"rendered":"To box or not to Box? That is the question!"},"content":{"rendered":"<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Discussions on <a href=\"https:\/\/www.reddit.com\/r\/programming\/comments\/6biv99\/box_or_not_to_box_that_is_the_question\/?ref=share&amp;ref_source=link\">reddit<\/a>, <a href=\"https:\/\/news.ycombinator.com\/item?id=14351418\">hacker news<\/a>. <\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Recently I&#8217;ve noticed that the <b>Equal <\/b>method from our <b>ValueTuple <\/b>(*)<b> <\/b>struct generates significant memory traffic (~1Gb). That was a bit of a surprise to me. This struct is well designed and was used pretty heavily in many performance critical scenarios. Here how the struct looks like:<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true\">public struct ValueTuple&lt;TItem1, TItem2&gt; : IEquatable&lt;ValueTuple&lt;TItem1, TItem2&gt;&gt;\r\n{\r\n    public TItem1 Item1 { get; }\r\n    public TItem2 Item2 { get; }\r\n\r\n    public ValueTuple(TItem1 item1, TItem2 item2)\r\n        : this()\r\n    {\r\n        Item1 = item1;\r\n        Item2 = item2;\r\n    }\r\n\r\n    public override int GetHashCode()\r\n    {\r\n        \/\/ Real implementation is a bit more complicated. Not a simple XOR\r\n        return EqualityComparer&lt;TItem1&gt;.Default.GetHashCode(Item1) ^\r\n            EqualityComparer&lt;TItem2&gt;.Default.GetHashCode(Item2);\r\n    }\r\n\r\n    public bool Equals(ValueTuple&lt;TItem1, TItem2&gt; other)\r\n    {\r\n        return (Item1 != null &amp;&amp; Item1.Equals(other.Item1)) &amp;&amp;\r\n                (Item2 != null &amp;&amp; Item2.Equals(other.Item2));\r\n    }\r\n\r\n    public override bool Equals(object obj)\r\n    {\r\n        return obj is ValueTuple&lt;TItem1, TItem2&gt; &amp;&amp;\r\n            Equals((ValueTuple&lt;TItem1, TItem2&gt;)obj);\r\n    }\r\n    \/\/ Other members, like equality operators are omitted for brevity\r\n}<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt; line-height: normal;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">(*) Our ValueTuple was implemented way before the one that was shipped with VS 2017, and our implementation is immutable. So even today we can&#8217;t switch to the implementation from the .NET Framework.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Nothing special. Methods <b>Equals <\/b>and <b>GetHashCode <\/b>are overriden to avoid boxing allocation (more on this later in the post). Null check to avoid <b>NullReferenceExcecption<\/b> if <b>Item1 <\/b>or <b>Item2 <\/b>are reference types. Null check potentially could have caused a boxing allocation if the JIT would have leave a check for null if <b>Item1<\/b> or <b>Item2<\/b> are structs. But luckily it is smart enough to eliminate the check in this case. Everything is simple and straightforward. Right? Almost.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">In our case the memory traffic was generated not for every <b>ValueTuple <\/b>case, but only for a specific one: <b>HashSet&lt;ValueTuple&lt;int, MyEnum&gt;&gt;<\/b>. Ok. This helps a bit. Right?<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Let&#8217;s see what will happen when the <b>Equals <\/b>method is called to compare two instances of <b>ValueTuple&lt;int, MyEnm&gt;&gt;<\/b> type:<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">\/\/ Compiler's view of the world\r\npublic bool Equals(ValueTuple&lt;int, MyEnum&gt; rhs)\r\n{\r\n    return Item1.Equals(rhs.Item1) &amp;&amp; Item2.Equals(rhs.Item2);\r\n}<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">For the <b>Item1<\/b> we&#8217;d have a call to <b>int.Equals(int)<\/b>, and for <b>Item2 <\/b>we&#8217;d have a call to <b>MyEnum.Equals(MyEnum)<\/b> method. For the first case nothing special will happen, but for the second case the method call will cause a boxing allocation!<\/span><\/span><\/span><\/p>\n<h2 style=\"margin: 2pt 0in 0pt; line-height: 14pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri Light;\"><span style=\"font-size: 13pt; color: #2e74b5;\">&#8220;When&#8221; and &#8220;Why&#8221; boxing happens?<\/span><\/span><\/span><\/h2>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">We used to think that boxing happens only when an instance of a value type is explicitly or implicitly converts to an object or to an interface:<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">int n = 42;\r\nobject o = n; \/\/ Boxing\r\nIComparable c = n; \/\/ Boxing<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">But the reality is slightly more complicated. The JIT and the CLR will have to box an instance in some other cases: for instance, to invoke a method defined in &#8220;reference type&#8221; section of a value type.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"color: #000000;\"><span style=\"font-size: 11pt;\">All custom structs are implicitly sealed and derived from the special class: <b>System.ValueType<\/b>. All value types have &#8220;value semantic&#8221; meaning that the object\u2019s default referential equality is no longer suitable for them. To enforce the new semantic <b>System.ValueType<\/b> provides a special implementation for two methods: <b>GetHashCode<\/b> and <\/span><b><span style=\"font-size: 11pt;\">Equals.<\/span><\/b><\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">But default implementation has two problems: the performance is very bad (**) because it may use reflection and boxing will happen for every method invocation.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"color: #000000; font-family: Calibri;\"><span style=\"font-size: 11pt;\">(**) The performance of the default implementation of <b>ValueType.Equals <\/b>and <b>ValueType.GetHashCode <\/b>can vary significantly based on the structure of a given value type. If the struct doesn&#8217;t have pointers and is &#8220;packed&#8221; correctly, then bit-wise comparison is possible. Otherwise, reflection will be used that will cause a drastic performance degradation. See <\/span><\/span><\/span><span style=\"font-size: 11pt;\"><a><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u>CanCompareBits<\/u><\/span><\/span><\/a><\/span><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\"> implementation at the coreclr repo.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">The first issue is pretty well-known but the other one is more subtle: if the <\/span><\/span><\/span><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">struct does not override a method, boxing will happen!<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">struct MyStruct\r\n{\r\n    public int N { get; }\r\n \r\n    public override int GetHashCode() =&gt; N.GetHashCode();\r\n \r\n    public override bool Equals(object obj)\r\n    {\r\n        return obj is MyStruct &amp;&amp; Equals((MyStruct)obj);\r\n    }\r\n \r\n    public bool Equals(MyStruct other) =&gt; N == other.N;\r\n}\r\n \r\n\r\nvar myStruct = new MyStruct();\r\n \r\n\/\/ no boxing: MyStruct overrides GetHashCode\r\nvar hc = myStruct.GetHashCode();\r\n \r\n\/\/ no boxing: MyStruct overrides Equals\r\nvar equality = myStruct.Equals(myStruct);\r\n \r\n\/\/ boxing: MyStruct does not override ToString\r\nvar s = myStruct.ToString();\r\n \r\n\/\/ boxing: GetType is not virtual\r\nvar t = myStruct.GetType();<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">In the example above, the boxing will not happen in the first 2 cases, but will happen in the last two. Call to a method, defined in <b>System.ValueType<\/b> (like <b>ToString<\/b>, and <b>GetType<\/b> in this case) will cause boxing and call to an overridden method (like <b>Equals<\/b> and <b>GetHashCode)<\/b> \u2013 will not.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Now let\u2019s switch back to our example with <b>ValueTuple&lt;int, MyEnum&gt;<\/b>. User-defined enums are value types without an ability to override <b>GetHashCode<\/b> and <b>Equals<\/b>, and this means that every call to <b>MyEnum.GetHashCode<\/b> or <b>MyEnum.Equals<\/b> will cause an allocation.<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"color: #000000; font-family: Calibri;\"><span style=\"font-size: 11pt;\">But can we avoid it? Yes, by using <\/span><\/span><\/span><span style=\"font-size: 11pt;\"><a><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u>EqualityComparer&lt;T&gt;.Default<\/u><\/span><\/span><\/a><\/span><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\"> instance.<\/span><\/span><\/span><\/p>\n<h2 style=\"margin: 2pt 0in 0pt; line-height: 14pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri Light;\"><span style=\"font-size: 13pt; color: #2e74b5;\">How EqualityComparer avoids allocations?<\/span><\/span><\/span><\/h2>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">Let\u2019s get slightly simplified example and compare two ways of comparing enum values (pun intended): using <b>Equals<\/b> method and using <b>EqualityComparer&lt;T&gt;.Default<\/b>:<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">var s1 = new ValueTuple&lt;int, MyEnum&gt;(42, MyEnum.Foo);\r\nvar s2 = new ValueTuple&lt;int, MyEnum&gt;(42, MyEnum.Bar);\r\n \r\n\/\/ Will cause a boxing allocation\r\nbool r = s1.Equals(s2);<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"color: #000000; font-family: Calibri;\"><span style=\"font-size: 11pt;\">Let\u2019s use <\/span><\/span><\/span><span style=\"font-size: 11pt;\"><a><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u>BenchmarkDotNet<\/u><\/span><\/span><\/a><\/span><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\"> to prove that the first case causes an allocation and the other one does not (to avoid iterator allocation I\u2019m using a simple <b>foreach<\/b> loop and not something like <b>Enumerable.Any<\/b> or <b>Enumerable.Contains<\/b>): <\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">[MemoryDiagnoser]\r\npublic class EnumComparisonBenchmark\r\n{\r\n    public MyEnum[] values = \r\n            Enumerable.Range(1, 1_000_000)\r\n              .Select(n =&gt; MyEnum.Foo).ToArray();\r\n \r\n    public EnumComparisonBenchmark()\r\n    {\r\n        values[values.Length - 1] = MyEnum.Bar;\r\n    }\r\n \r\n    [Benchmark]\r\n    public bool UsingEquals()\r\n    {\r\n        foreach(var n in values)\r\n        {\r\n            if (n.Equals(MyEnum.Bar)) return true;\r\n        }\r\n        return false;\r\n    }\r\n \r\n    [Benchmark]\r\n    public bool UsingEqualityComparer()\r\n    {\r\n            var comparer = EqualityComparer&lt;MyEnum&gt;.Default;\r\n        foreach (var n in values)\r\n        {\r\n            if (comparer.Equals(n, MyEnum.Bar)) return true;\r\n        }\r\n        return false;\r\n    }\r\n}<\/pre>\n<pre class=\"lang:default decode:true \">                Method |      Mean |      Gen 0 |  Allocated |\r\n---------------------- |----------:|-----------:|-----------:|\r\n           UsingEquals | 13.300 ms | 15195.9459 | 48000597 B |\r\n UsingEqualityComparer |  4.659 ms |          - |       58 B |<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">As we can see, the regular <b>Equals<\/b> call causes a lot of allocations for no reason. Moreover, <b>EqualityComparer<\/b> is way faster, although in my case I haven\u2019t seen any difference after I\u2019ve switched the implementation to use <b>EqualityComparer<\/b>. The main question is: how does <b>EqualityComparer<\/b> do this?<\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span style=\"color: #000000;\"><span style=\"font-family: Calibri;\"><b><span lang=\"EN\"><span style=\"font-size: 11pt;\">EqualityComparer<\/span><\/span><\/b><span style=\"font-size: 11pt;\"><span lang=\"EN\"> is an abstract class that provides the most suitable comparer based on a given type argument via <b>EqualityComparer&lt;T&gt;.Default<\/b> property. Main logic resides in method <\/span><\/span><\/span><\/span><span style=\"font-size: 11pt;\"><a><b><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u>ComparerHelpers.CreateDefaultEqualityComparer<\/u><\/span><\/span><\/b><\/a><span lang=\"EN\"><span style=\"color: #000000; font-family: Calibri;\"> and in case of enums it delegates it to another helper method \u2013 <\/span><\/span><a><b><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u>TryCreateEnumEqualityComparer<\/u><\/span><\/span><\/b><\/a><\/span><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">. The last method then checks the underlying type of the enum and creates special comparer instance that does some nasty tricks:<\/span><\/span><\/span><\/p>\n<pre class=\"lang:default decode:true \">[Serializable]\r\ninternal class EnumEqualityComparer&lt;T&gt; \r\n    : EqualityComparer&lt;T&gt; where T : struct\r\n{\r\n    [Pure]\r\n    public override bool Equals(T x, T y)\r\n    {\r\n        int x_final = System.Runtime.CompilerServices\r\n           .JitHelpers.UnsafeEnumCast(x);\r\n        int y_final = System.Runtime.CompilerServices\r\n           .JitHelpers.UnsafeEnumCast(y);\r\n        return x_final == y_final;\r\n    }\r\n \r\n    [Pure]\r\n    public override int GetHashCode(T obj)\r\n    {\r\n        int x_final = System.Runtime.CompilerServices\r\n           .JitHelpers.UnsafeEnumCast(obj);\r\n        return x_final.GetHashCode();\r\n    }\r\n}<\/pre>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><a><span lang=\"EN\"><span style=\"color: #0563c1; font-family: Calibri;\"><u><span style=\"font-size: 11pt;\">EnumEqualityComparer<\/span><\/u><\/span><\/span><\/a><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\"> converts a nenum instance to its underlying numeric value using <b>JitHelpers.UnsafeEnumCast<\/b> with a following comparison of two numbers.<\/span><\/span><\/span><\/p>\n<h2 style=\"margin: 2pt 0in 0pt; line-height: 14pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri Light;\"><span style=\"font-size: 13pt; color: #2e74b5;\">So, what was the final fix?<\/span><\/span><\/span><\/h2>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 10pt; line-height: 13pt;\"><span lang=\"EN\"><span style=\"font-family: Calibri;\"><span style=\"font-size: 11pt; color: #000000;\">The fix was very simple: instead of comparing values using <b>Item1.Equals<\/b> we\u2019ve switched to <b>EqualityComparer&lt;T&gt;.Default.Equals(Item1, other.Item1)<\/b>.<\/span><\/span><\/span><\/p>\n<h2 style=\"margin: 2pt 0in 0pt; line-height: 14pt;\"><span style=\"font-family: Calibri Light;\"><span style=\"font-size: 13pt; color: #2e74b5;\">Additional References<\/span><\/span><\/h2>\n<p class=\"MsoListParagraphCxSpFirst\" style=\"margin: 0in 0in 10pt 0.5in; line-height: 13pt; text-indent: -0.25in;\"><span style=\"color: #000000;\"><span style=\"font-family: Symbol;\"><span style=\"font-size: 11pt;\">\u00b7<\/span><\/span><span style=\";line-height: normal;\"><span style=\"font-family: Times New Roman;\"><span style=\"font-size: 7pt;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span><\/span><\/span><\/span><a href=\"https:\/\/github.com\/dotnet\/corefx\/pull\/14187\">Remove usage of EqualityComparer from ValueTuple&#8217;s GetHashCode.<\/a><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\" style=\"margin: 0in 0in 10pt 0.5in; line-height: 13pt; text-indent: -0.25in;\"><span style=\"color: #000000;\"><span style=\"font-family: Symbol;\"><span style=\"font-size: 11pt;\">\u00b7<\/span><\/span><span style=\";line-height: normal;\"><span style=\"font-family: Times New Roman;\"><span style=\"font-size: 7pt;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span><\/span><\/span><\/span><a href=\"https:\/\/github.com\/dotnet\/coreclr\/issues\/8143\">GetHashCode should not box enums in generic methods.<\/a><u><\/u><\/p>\n<p class=\"MsoListParagraphCxSpLast\" style=\"margin: 0in 0in 10pt 0.5in; line-height: 13pt; text-indent: -0.25in;\"><span style=\"color: #000000;\"><span style=\"font-family: Symbol;\"><span style=\"font-size: 11pt;\">\u00b7<\/span><\/span><span style=\";line-height: normal;\"><span style=\"font-family: Times New Roman;\"><span style=\"font-size: 7pt;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span><\/span><\/span><\/span><a href=\"https:\/\/github.com\/dotnet\/corert\/pull\/2117\">Optimize calls to enum\u2019s GetHashCode\/Equals.<\/a><u><\/u><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discussions on reddit, hacker news. Recently I&#8217;ve noticed that the Equal method from our ValueTuple (*) struct generates significant memory traffic (~1Gb). That was a bit of a surprise to me. This struct is well designed and was used pretty heavily in many performance critical scenarios. Here how the struct looks like: public struct ValueTuple&lt;TItem1, [&hellip;]<\/p>\n","protected":false},"author":4004,"featured_media":37840,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[6700],"tags":[6701,6695],"class_list":["post-535","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-internals","tag-code-review","tag-seteplia"],"acf":[],"blog_post_summary":"<p>Discussions on reddit, hacker news. Recently I&#8217;ve noticed that the Equal method from our ValueTuple (*) struct generates significant memory traffic (~1Gb). That was a bit of a surprise to me. This struct is well designed and was used pretty heavily in many performance critical scenarios. Here how the struct looks like: public struct ValueTuple&lt;TItem1, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/4004"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=535"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/535\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=535"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=535"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}