Replies: 54 comments
-
This sounds like a serialization issue, not a language issue. As you yourself say, it's horrible that JavaScript has two ways of saying |
Beta Was this translation helpful? Give feedback.
-
@vhe1 null itself is a billion-dollar mistake and you want to just square it. It's JS problems that it has two entities to describe the almost same thing - absence of something. In my practice no one cares if value is not setted at all or it's just an unusable value. If field is required - you are rising an error, if it isn't then both are valid. But you have a lot of problems with |
Beta Was this translation helpful? Give feedback.
-
I did not say that "it's horrible that JavaScript has two ways of saying null", I said it's horrible that we can't use the information contained in this in a typed backend. Re "null is a billion dollar mistake", that's just wrong. The problem is not that there is null but that there is just one of it, forced to express two different intents. (Please remember the discussons in SQL. They focused precisely on the fact that it was not clear which null.) Having two different nulls solves that. |
Beta Was this translation helpful? Give feedback.
-
@vhe1 links to an RFC for JSON Merge Patch, which is an actual specification that differentiates between undefined and null. So it may not be a choice to "not think about it", if you need to interact with a system that uses that format. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
@vhe1 The problem with I think what you should do is to use the type system to your advantage: instead of a property of some type public struct Value<T>
{
public static Value<T> Undefined { get; }
public static Value<T> Null { get; }
public static Value<T> Create(T value); // throws if value is null
public bool IsUndefined { get; }
public bool IsNull { get; }
public T Value { get; } // throws exception when IsUndefined == true or IsNull == true
} Then you teach your JSON serializer about There is no need to pollute all of C# with this. |
Beta Was this translation helpful? Give feedback.
-
I've tried stuff along those lines but either it looks horrible in any swagger definition or it has a hole somewhere else. But I'll try some more then. Thanks a lot for bothering! |
Beta Was this translation helpful? Give feedback.
-
Newtonsoft.Json.NullValueHandling.Ignore |
Beta Was this translation helpful? Give feedback.
-
aluanhadad: How does this help me during deserialization? |
Beta Was this translation helpful? Give feedback.
-
@vhe1 1 I'm may have written something a bit wrong below, I am really tired 😪 So the simple scenario is C# producer, using Newtonsoft (the JSON one, not the DSON one), paired with a JavaScript consumer using To do this, we need to form a semantic bridge, across JSON, from C# types (CLR) to JavaScript values (ECMAScript) types. JSON has structural types only. There are no named constructs, it is nice and simple. It also happens to be a rough subset of ECMAScript literals which makes this mapping relatively straightforward. The idea is basically to adopt the view that We can enforce this as follows: class Person
{
public string Name { get; set; }
public int? Age { get; se; }
}
var person = new Person
{
Name = "Anders"
}; // Age is null JSON {
"name" : "Anders"
} JavaScript // literal from JSON.parse(response.data)
const person = {
name: 'Anders'
}; So we don't know the age of our person on either side and our REST interface allows it to be unspecified. So all is well. Now when the JavaScript client wants to send me some values, he can do anything he wants
const person = {
name: 'Douglas'
};
request.data = JSON.stringify(person); // JSON => { "name": "Douglas" };
const person = {
name: 'Douglas',
age: null
};
request.data = JSON.stringify(person); // JSON => { "name": "Douglas", "age": null }; Thanks to C# public HttpResponseMessage Post(Person person)
{
var person = JsonConvert.DeserializeObject<Person>(Model);
Console.WriteLine(person.Name); // => "Douglas"
Console.WriteLine(person.Age); // => null
} (1) This applies equally to TypeScript (obviously as TS is JS). Interestingly, while the community is somewhat divided, a fair number of ECMAScript experts such as Douglas Crockford, as well as the TypeScript team, have stated that |
Beta Was this translation helpful? Give feedback.
-
You are still trying to solve the wrong problem.
The problem I want to solve is to READ a json object according to rfc 7386 as I wrote in my initial feature request posting.
I'm not interested in creating such a json, I want to READ it and in the generated c# object distinguish between JSON null and JSON undefined, in order to properly deal with it according to that rfc.
So, according to rfc 7386, {name: "XXX", age: null} and {name:"XXX"} have two distinct meanings. The first one updates the name and /deletes the age from whatever persistence layer there is/, the second one updates the name and /leaves the age alone/.
|
Beta Was this translation helpful? Give feedback.
-
@vhe1 then you just should write your own deserializer and wrap every propery with |
Beta Was this translation helpful? Give feedback.
-
@Pzixel, I understand that, I was just replying to aluanhaddad. |
Beta Was this translation helpful? Give feedback.
-
@vhe1 I misunderstood your use case. You are dealing with partial updates. In that case, I think the solution is indeed what @HaloFour and @Pzixel are suggesting. You can wrap your fields in an optional value. You can configure your serializer to understand it, which is not hard. The |
Beta Was this translation helpful? Give feedback.
-
Sidebar: the R language has both NULL and NA. Missing values are represented by the symbol NA (not available). Having NA is really useful in stats, data science, etc... |
Beta Was this translation helpful? Give feedback.
-
I don't understand how checking a DOM will help? We still need to deserialize to a C# object, and the C# object needs a property with three possible states: value specified, explicit null value, or unspecified value. @Pzixel - I at least feel you understand the issue, thanks. 👍 The |
Beta Was this translation helpful? Give feedback.
-
How would you Serialise a C# object that had an undefined value for one of its properties? You'd end up putting in a feature request to add undefined to Json. And then you'd need to add reallyReallyUndefined to C#. And the never ending cycle continues... |
Beta Was this translation helpful? Give feedback.
-
IMO, the real problem is that the BCL doesn't have a proper stock |
Beta Was this translation helpful? Give feedback.
-
I've been writing C# code for the last 13 years and I've already mentioned several cases when an @theunrepentantgeek , does ACM advise against the very existance of @CyrusNajmabadi , in SQL you can choose which values to include in an INSERT and UPDATE statements, and WHERE clauses. Entity Framework Core handles these scenarios with its own workaround - object tracking.
The property will not be present in JSON - that's what |
Beta Was this translation helpful? Give feedback.
-
Turtles all the way down! No, by not specifying the property/value in JSON, then by definition it has an undefined value (neither a tangible value, nor null). Undefined does not get serialized/deserialized, as opposed to null which, as you know, can be serialized. |
Beta Was this translation helpful? Give feedback.
-
Why is this the only option? I can imagine taking code which uses the POCO and rewriting it to use the DOM. For something that has a very dynamic schema, this might even be preferable. |
Beta Was this translation helpful? Give feedback.
-
It sounds like people are talking about an API they'd like, or the behavior of existing APIs. I still haven't seen a use case fo C# having an actual undefined value. |
Beta Was this translation helpful? Give feedback.
-
Wouldn't 'undefined' be the same way? All these tools and apis would have to be updated to handle this new intrinsic value. If they can be updated to handle 'undefined', why can't they be updated to handle 'Optional'? |
Beta Was this translation helpful? Give feedback.
-
The crux of the problem seems to be the desire to have a distinct value (a sentinel value) that means don't overwrite. To illustrate, you can use null as the sentinel value that means keep the existing value: public class Person
{
public string FullName { get; private set; }
public string KnownAs { get; private set; }
public string FamilyName { get; private set; }
public void Patch(Person other)
{
if (other.FullName is not null) FullName = other.FullName;
if (other.KnownAs is not null) KnownAs = other.KnownAs;
if (other.FamilyName is not null) FamilyName = other.FamilyName;
}
} But that doesn't let you patch existing properties to null, because you're using null to indicate don't overwrite. So you introduce a new sentinel value, let's say undefined. public class Person
{
public string FullName { get; private set; }
public string KnownAs { get; private set; }
public string FamilyName { get; private set; }
public void Patch(Person other)
{
if (other.FullName is not undefined) FullName = other.FullName;
if (other.KnownAs is not undefined) KnownAs = other.KnownAs;
if (other.FamilyName is not undefined) FamilyName = other.FamilyName;
}
} The problem is, now you can't patch existing properties to undefined, because that's the sentinel value that indicates don't overwrite. All you've done is to move the problem down the road one step. The problem is caused by the use of a sentinel value instead of a distinct flag. What I did, when I needed to solve this exact problem, was to create a struct that captured whether I'd specified a value or not. With epic amounts of imagination, I called it |
Beta Was this translation helpful? Give feedback.
-
And with NoSQL systems, this is actually a perfectly valid use-case. |
Beta Was this translation helpful? Give feedback.
-
So were all the API that use |
Beta Was this translation helpful? Give feedback.
-
@vdachev Exactly. Task was added to the framework and the libraries updated to use it. No need to make a language change here. This should likely be moved to corefx with a request to make a suitable Optional/Some/None type for this purpose. |
Beta Was this translation helpful? Give feedback.
-
The point in this discussion is that there are lots of scenarios when an Or course, it all depends on the way such support is implemented:
|
Beta Was this translation helpful? Give feedback.
-
As mentioned, the standard solution would be from Corefx, not from C#. C# is not the standard. It's one of many languages here. You want a corefx solution so that tehse libraries can actually adopt it. I recommend you open a bug there. If tehre is some library that is created, and it becomes popular enough, there can be consideration around if there should be a language feature.
I don't know what this means. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
As web backend developer, the thing that is hardest for me is to deal with the two ways javascript frontends have to do nulls, undefined (member not in json) and null (member in json and has null assigned).
I'm constantly in discussions with my client developers and this is no fun at all.
The typical usage is described in rfc 7386, it's obvious, sensible and there is no way at all for us in the backend to deal with it because we only have null.
Of course, we could deserialize the json into Dynamic or a set of nested Dictionary<String,Object> structures but that would lose all type safety and convenience. Then we might as well use Typescript (which has it) and node.js for backend programming.
This is the biggest gripe I currently have.
So, is there a way to allow us backend developers to correctly derive the client's intent from a json with nulls and missing members?
Maybe another method for ValueType would do it for the simple stuff? No idea about references though. On the other hand, C++ has so many pointers now, maybe c# can stand another reference type?
Beta Was this translation helpful? Give feedback.
All reactions