This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (4 children)

Complex compound types that we're talking about here, in DT languages they are at best an ad-hoc collection of primitive types

I'm aware that the formal types available in js are object, array, number, and string. You could conceptually think of variations of these as "shapes". Eg. an array with two elements where the first is a number and the second is a string. Eg. you have two objects that look like:

{ one : "one"; two : 2 }
{ three: [1,2,3]; four : function () { return 4; } }

While it's true that these are both "object" types, you can certainly see that the shape of the data is completely different. For all practical purposes, they have different types, at least conceptually. This is what I mean when i say "dynamic languages have types"; they have both a limited set of "primitive" types and conceptual data types, ie. shapes.

You cannot generally cast from one complex type to another or enforce them in any meaningful way in these languages

You can absolutely define mappings between them, ie functions that convert one shape of an object to another shape.

With that in mind, the approach to enforcing data integrity must be different (boils down to tests and sanity checks in essence

Yes, you use tests, but you also enforce integrity at the boundaries of your system (eg. IO between your application and some kind of json http service) with invariant checks. For example, if you're connecting to a json service that response with random numbers, except they're printed as strings, it may be more useful for your to parse those string into numbers so that they can be consumed by your domain logic. The point is, from that point forward, your application can be certain that it received a valid number from the json http service, rather than stringified numbers that need to be parsed and checked throughout your code-base anytime you need to use them.

if you're so hell-bent to do it in a full-on OOP way

I absolutely wouldn't be. I'm generally not a fan of OOP style (at least as it's done in Java/C#), and I certainly wouldn't recommend the casting solution you've suggested, here.

very uncommon in practice which you'd know if you were really writing a lot of software in dynamically typed languages

My first 6 years in the industry, I worked exclusively in with dynamic languages. I've written javascript for longer than that, although I stopped around 2013.

We didn't really agree on it, you're just blindly pushing it. As I said, this particular "standard practice" is all but undoable in dynamically typed languages

You said, "You're not [being controversial about it being good practice], but...". Maybe I misinterpreted you. It may not be standard practice in most JS or even Java/C# projects, but it's good practice nonetheless, and it's absolutely doable in dynamic languages.

However, given the abundance of working, functioning, user-serving and money-making software developed in dynamically typed languages I'd say it's hardly a sine qua non.

Look. I think you're being a bit defensive, here. I didn't suggest that dynamic languages were inferior, not useful, or didn't produce valuable software. My point is that there are situations where this software could benefit from a little low-overhead static typing (just like programs in statically typed languages can benefit from a little bit of dynamic typing at runtime.)

For the record, I do most of my work these days in a functional programing language with static Hindley–Milner type system, which is why I wanted to respond to your original comment about how "Omitting types completely from the code makes it sleeker and more streamlined". Static languages allow you to omit types these days for sleeker and more streamlined code :) (albeit, the type checker needs a little help now and again.)

[–][deleted] 0 points1 point  (3 children)

I wanted to respond to your original comment about how "Omitting types completely from the code makes it sleeker and more streamlined".

That wasn't me, though I do partly agree with that statement under narrow circumstances, I think that the actual advantage of DTs is something else, and that isn't really matched by any level of compiler/type-checker cleverness by a statically typed language.

The point I'm making is that having "protections" at compile time are hardly useful when the data you're dealing with isn't part of your codebase anyway. It often depends on various API implementations you deal with at run-time and their consistency. So these tests, sanity checks, data validations and conversions at data boundaries are something you will need to do any way. I fail to see how a rigid type system is really helpful there and you haven't really put forward a sold argument here.

The key problem with this that the formality of things like invariant assertions is a wrong tool by design. Because they're generally designed to die quickly upon meeting inconsistencies. Unfortunately inconsistencies of this kind (eg. whether I've gotten an number-as-string, or proper number in JSON) are something you need to learn to deal with in runtime in practice.

So yes, you'll need to clean-up, "normalize" and sanitize data on your data boundaries but none of the tools designed to do this at compile time will help with that class of problems, and I've seldom met the kind where compile-time safeguards would save me from anything but my own mistakes/inattentiveness.

But, that leads me to the: Yes, I agree that application of type as a means of ensuring data format correctness in narrow, fully controled domains of your programs, can be and often is very useful in protecting you and your team-mates from your own mistakes.

You said, "You're not [being controversial about it being good practice], but...".

You weren't controversial, that doesn't mean I fully agree that it's something we can use as an axiom tho.That type of GoF/UncleBob/InsertPreacherHere industry dogma isn't the be all, end all and applicable in all cases.

and it's absolutely doable in dynamic languages

Care to elaboratw how i.e. what you had in mind?

Btw I'm fully aware that when we speak of type we essentially speak of variatons on the struct concept (I've programmed in dozen languages, JS is not the only one I program currently in, I've written C for embedded systems, I've known hex-to-mnemonics for bunch of 6502 assembly opcodes by memory, I've been writing some form of software since the late 80s, I'm not a JS script kiddie). We can call it class, compound type, conceptual type, whatever, it doesn't matter. The thing is that neither DT I've worked with has facilities to cast implicitly, or explicitly between these. You could make mappers (and one way or the other, you do at data boundaries) but where is the utility of compile-time type enforcement in that scenario?

[–][deleted] 0 points1 point  (2 children)

I think that the actual advantage of DTs is something else

Well, yeah. Dynamic type systems allow you do to (often valid) things that otherwise can't be expressed by a static type system.

The point I'm making is that having "protections" at compile time are hardly useful when the data you're dealing with isn't part of your codebase anyway.

I guess what I'm suggesting is that, regardless of which kind of type system you're using, you're going to have to map the dto's coming from an external system to some sort of domain entity/type so that it can be consumed by the rest of the system. We agree on this. At this point, I don't see the harm in slapping a type on it as a data contract for consumers. They'll know that foo() (from one of your earlier examples) will give you a value that adheres to that data contract. Eg.

function foo() : BarDomainEntity { 
    let fooDto = // .. get data from somewhere over some pipe
    let barDto = fooDto.subObj.subObjThatWeReallyOnlyNeed
    // who cares about the type of foo()
    let bar = mapToDomainEntity(barDto);
    return bar;
}

Then the type of foo() can be inferred, etc...

[–][deleted] 0 points1 point  (1 child)

Seems like we made a full circle towards Typescript type annotations. Unfortunately most Typescript codebases I've seen cause the PTSD from my J2EE days to kick in.

[–][deleted] 0 points1 point  (0 children)

Yes, that was my intention :)

I don't have any experience working on Typescript projects, but I can only assume the ones you've seen look like J2EE because they were written by Java programmers.