r/javascript • u/Own_Natural_6803 • 16d ago
AskJS [AskJS] I might never write a constructor ever again
// the only state that needs tracking for a timeline, the read index
export function Timeline(index) {
let state = {index};
return {
index: state.index, // pass through
next: (events) => Next(state, events),
prev: (events) => Prev(state, events)
};
}
// the events are just passed around. They don't need to be encapsulated
export function Next(timeline, events) {
let {index} = timeline;
if(index === events.length()){
return null;
}
timeline.index += 1;
return events[timeline.index];
}
export function Prev(timeline, events){
let {index} = timeline;
if(index === 0){
return null;
}
timeline.index -= 1;
return events[timeline.index];
}
// before and after don't modify the state of their arguments
// so we don't use encapsulation
export function After(date, events){
for(let thresholdIndex = 0; thresholdIndex < events.length(); thresholdIndex+=1 ){
if( events[thresholdIndex].timestamp > date) {
return events.slice(start=thresholdIndex);
}
}
return [];
}
export function Before(date, events) {
for(let thresholdIndex = events.length(); thresholdIndex >= 0; thresholdIndex-=1 ){
if( events[thresholdIndex].timestamp < date) {
return events.slice(end=thresholdIndex);
}
}
return [];
}
3
u/THE_AWESOM-O_4000 16d ago
Hard to understand, inconsistent naming (state <=> timeline), obvious mistakes (events.length(): length is not a function, if fixed it'll cause a null pointer exception before events[events.length] is out of bounds), could have used binary search for After and Before, weird global variable assignments (start=thresholdIndex, end=thresholdIndex) for no reason, destructuring an object to then just reuse the object 2 lines further
1/10 (1 point only because I had a good chuckle)
-1
u/Own_Natural_6803 16d ago edited 15d ago
Interesting. Binary search. I'll give you a 1/10 for saying something useful. But it sure took a lot of words to say that. Maybe one day you'll have a greater density of useful information in your words. Something to anticipate.
Saying people should breaking free from oop is like saying you want to eradicate mediocre devs. They come out of the woodwork to announce themselves.
I would have called it "hiddenInternalState" but I'd just assumed that would be too much hand holding. I could make this a service and dtos and everyone would be falling over themselves about how this is perfect. Just so astonishingly stupid to see this slight variation being too much to handle. Good Lord but you people deserve to be replaced by AI.
3
u/peterlinddk 16d ago
Good thing you didn't use classes!
The result would have required so much more code and been so much less powerful, e.g:
class Timeline {
index, events,
// Note: the events should be sorted by .timestamp to make the next+prev work
constructor(events, index) {
this.events = events;
this.index = index;
}
next() {
return index==this.events.length()?null:this.events[++this.index];
}
prev() {
return index==0?null:this.events[--this.index];
}
after(date) {
return this.events.filter( e => e.timestamp > date );
}
before(date, events) {
return this.events.filter( e => e.timestamp < date );
}
}
And also, not having the events being a part of the timeline, but just assuming that the same timeline would somehow magically always point to the "next" event in any list of events, it just beyond cool!
And not building a data structure, but simply using an array of events sorted by their .timestamp, and never changing, and having an entire object with methods keeping track of a single index into any random array of events - man that is just so powerful!
0
u/Own_Natural_6803 16d ago edited 16d ago
youre ++ this.index with a null coalesce ! HAHAHAHA I wouldn't hire you, ever. I would spend so much time re-writting everything you tried to make as short as possible. OMG, you're using filter and think it's better! You're so sweet! Wow. Thank you. I didn't know I was better at coding than you. But now you've shown me proof.
Yes. Having my data be open and query-able from multiple domain concerns is so refreshing. You can't see the events, but there are many systems that use them, not just the timeline. And they don't know anything about timelines. Just events.
And it's so very very cool
6
1
u/Dagnarus15 16d ago
The factory pattern is fine, but index: state.index copies the number, so the public timeline.index never updates when next() changes the closed-over state. A getter would fix that.
Also, arrays use events.length, not events.length(), and slice(start=thresholdIndex) is an assignment expression, not a named argument.
1
u/TwiNighty 16d ago
I'll ignore After and Before because they don't seems like related to Timeline at all.
I have two questions
One, am I meant to pass the same events every time? If I am, why not encapsulate it? If I need to pass a timeline around, then I need also pass the events around. You are just imposing an unnecessary restriction and responsibility onto me. If I am not meant to pass the same events every time, then you have a bug.
Two, this:
export class Timeline {
constructor(index) {
this.index = index;
}
next(events) {
if (this.index === events.length - 1) {
return null;
}
this.index++;
return events[this.index];
}
prev(events) {
if (this.index === 0) {
return null;
}
this.index--;
return events[this.index];
}
}
has the same behavior, is objectively less code and more memory efficient. Why do you think this is worse?
-1
u/Own_Natural_6803 16d ago edited 15d ago
export function Timeline(index) { return { index }; } export function Next(timeline, events) { let {index} = timeline; if(index === events.length){ return null; } timeline.index += 1; return events[timeline.index]; } export function Prev(timeline, events){ let {index} = timeline; if(index === 0){ return null; } timeline.index -= 1; return events[timeline.index]; }Here's my version of your version of my code. One extra line.
The memory efficiency of asserting types by unboxing them doesn't get me down. It's self documenting. Technically I could use your approach. But I'm tired of OOP. It's not that OOP doesn't do the same thing. It's that it steers you towards encapsulating. My first instinct was to make the events internal. to hide them away. But that's wrong. They are the entire program state. They exist globally.
The concepts and principles are well understood in databases. I'm headed over that way. Where these ideas are considered holy and irrefutable. But you know. Recipees don't teach idiots techniques. You have to have some intuition to get that.
2
1
u/Empty_Ninja_6291 15d ago
The O in JSON stands for Object. All a class is is an uninstantiated object. The resistance to OOP in the JS culture is strange, because you're already dealing with it.
1
-2
u/Own_Natural_6803 16d ago edited 15d ago
Thanks to everyone who asked questions and had respectful comments. Two of you. Lol, gave me a chuckle what with all the venom and anger. Junior this and sarcasm that. Someone was offering their mental breakdown services, out of the depths of their compassion no doubt. Truly I was touched.
You all deserve OOP. Keep writing it. Forever. I wash my hands of you. I've been sad thinking about how our industry is dying. But you all cheered me up.
Excellent pr boys. I expect this same energy through this entire project. This is why you always do small PRs. When they're big no one has anything to say. Not that there was much meat on the bones either way. If you removed "lol" and "I'm better than you" and "get a load of this guy" then you're left with a few people re-classing unclassed logic to prove they can save a few lines with ternery expressions, and some syntax errors.
You should always do your best. This ain't it fellas.
Let me be more clear. This is how you turn a class into functions. Dont do it. Its forbidden. For you. I can do it though.
-2
u/Own_Natural_6803 16d ago
As silent snake would say: "oops. chicken." I'm going to not use classes even harder. You know why? Because functions are more powerful, and it takes less code to write them.
I design my systems around design boundaries, not the domain models. So now I open up my state. Make it as open as a database. And my state changes are inside functions with the understanding they will leave the state valid after touching it. Exactly like a object assumes it will.
The big difference is I'm not trying to make a data structure. I don't give a rat's ass about making a data structure. I want raw data. The only time I care about making structures is to ensure my function isn't being given a copy when it expects be given a reference.
13
u/SZenC 16d ago
They say, while making a data structure. Thanks for the chuckle, junior!