Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
vodkat
Jun 30, 2012



cannot legally be sold as vodka

MALE SHOEGAZE posted:

vim is suiting my needs. I'm sure sublime would be good

re: python indenting. I got a gently caress ton of errors the other day after I copied and pasted poo poo from ipython to sublime and even thought all the indents looked fine I had to go through and retab all the offending lines :smith:

Adbot
ADBOT LOVES YOU

the talent deficit
Dec 20, 2003

self-deprecation is a very british trait, and problems can arise when the british attempt to do so with a foreign culture





pepito sanchez posted:

MonocQc curious what IDE do you use for your erlang? i am hating emacs for haskell and elixir. or it's hating me. or both.

i have been trying this out: https://www.jetbrains.com/idea/features/erlang.html

i mostly use vim tho

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

vodkat posted:

I had to go through and retab all the offending lines :smith:

sublime doesn't have find/replace?

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

NihilCredo posted:

sublime doesn't have find/replace?
find/replace on whitespace in python sounds like a dangerous game

MononcQc
May 29, 2007

Captain Foo posted:

1) I'm not sure!
2) It would be cool, yes
3) I don't know. Probably.
4+5) The state of the game depends on the votecount: During the Day Phase, the players vote on who should be eliminated based on various factors, once a majority is reached that player is eliminated and it becomes Night, at Night the Scum is allowed to eliminate another player. If at this point the Scum make up 50% of the game or more, they win. Otherwise the game continues.

I suppose the state that defines the game itself would be the Alive Players List, the Votecount, and the Phase.

Each Player minimally has a Name, an Alignment, a Current Vote, and a Public Suspicion. I would also like to be able to give each Player a few Personality Attributes which would modify their behavior - e.g. even if the base behavior is always "vote for the Other Player with the highest Suspicion," I should be able to have each Player have e.g. a different minimum threshold for Voting, or a higher likelihood of Voting a Player that is currently Voting for them.
A way to organize this one that's interesting is to make it fully asynchronous by sending all player and server actions to a process that acts like an event sync (it can store them transient or permanently if you want game logs).

The game server and all player middlemen processes subscribe to the event sync and write to it.

So the way to think about this one is to have the main server that's a big state machine transitioning between day -> night, during the day phase it receives votes from players and tallies them. It can then transition to night on getting the right vote count (and inserts a message about it to players), triggers the scum actions in the same way, and so on. The thing can just wait for votes from players it has in a list with their status.

Meanwhile the players can subscribe to these events too, relay them to actual human players, and filter stuff in according to the time of the day related by the server, and filter out according to which events the player is allowed to see.

This ends up being a bunch of independently set state machines communicating over messages, but the player process has nearly nothing to know about game mechanics, and can even be used to trigger default actions or route to an AI if you wanted to.

pepito sanchez posted:

MonocQc curious what IDE do you use for your erlang? i am hating emacs for haskell and elixir. or it's hating me. or both.
I use vim + tmux + an Erlang shell. From my own experience regarding my self-directed learning, I make better progress when I throw myself in the deep-end and force myself to learn all the basics to do the least amount of progress. It starts slow but then I feel I have a good intuitive knowledge of how things work. So my dev environment tends to be very minimalist and I have to do everything manually or quickly write tools or abstractions to prevent problems. Those haven't been big negatives so far, though if tools exist and I need to be done quick, I'll be glad to use them.

It's just that my entire Erlang experience started from a hobbyist standpoint and the tooling ended up usable outside of any specific editor so I was fine with that.

Yep. There's a quick reference to my setup there.

Shaggar
Apr 26, 2006
lets talk about terrible programs. Apparently safari on ios eats taps on links under certain situations so you have to write some hacks to force it to actually treat the tap as a click on the link. gently caress you apple your poo poo is garbage

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Jeffrey of YOSPOS posted:

find/replace on whitespace in python sounds like a dangerous game

he said he'd just copy/pasted that stuff from outside. hold the selection, replace [ ]{4} with tab within the selection. don't see a problem unless there were string literals with lots of whitespace in there.

NihilCredo fucked around with this message at 22:08 on Nov 4, 2015

comedyblissoption
Mar 15, 2006

MALE SHOEGAZE posted:

i always spend time trying to make my code simple and composable but there is a part of me than sometimes wonders if it's sometimes a bit like premature optimization.

i work under the assumption that I'm never going to touch the code again and it's gonna need to be simple for the next guy, but the fact is, I frequently DO come back to the code and in a lot of cases, all that time spent on good code design is totally wasted because the overall approach was wrong or because requirements changed. So frequently, all that time spent on good code is wasted, and a 300 line function woulda worked just as well.
breaking stuff up into small composable functions is not such an undue burden that 300 line functions are excusable. it's generally easier to write a bunch of small composable functions than the equivalent 300 line function in the first place.

Barnyard Protein posted:

imo you shouldn't create a function just to make another function smaller unless the composition you create makes sense. short functions are a sign of a good design, but seems like saying "short is better" leads to short functions with bad design. i see this a lot. people have a class with a super long function, but they know Long Function Bad Thing. so they split it up into a bunch of no-return no-argument methods that manipulate the class fields, and one worker method that calls the other chunks.
you're completely right that just because you have short functions doesn't mean you have good design. a bunch of contextless short functions that just mutate global (or class) state and have no explicit inputs or outputs is potentially worse than just stuffing all the code into a giant function.

the key here to good design is trying to as much as reasonably possible structure your program as the composition of small, pure or kind-of-pure functions. as much as possible, make the output of a function depend on its inputs. unfortunately a lot of languages kind of work against doing this right and you kind of have to do half-assed pure functions, but it's certainly better than alternatives.

FamDav
Mar 29, 2008

Barnyard Protein posted:

they split it up into a bunch of no-return no-argument methods that manipulate the class fields

i had someone come to my desk and shout at me after i rejected this kind of thing in a code review and wouldn't budge.

eschaton
Mar 7, 2007

Don't you just hate when you wind up in a store with people who are in a socioeconomic class that is pretty obviously about two levels lower than your own?

NihilCredo posted:

sublime doesn't have find/replace?

I'd expect any programmer's editor to have entab/detab commands, to convert an entire file from one to the other

of course even better is to have a mode line in the file and an editor that respects it...

vodkat
Jun 30, 2012



cannot legally be sold as vodka

NihilCredo posted:

he said he'd just copy/pasted that stuff from outside. hold the selection, replace [ ]{4} with tab within the selection. don't see a problem unless there were string literals with lots of whitespace in there.

Yea there was probably a much neater way to fix this, its just for those 15 minutes I did spend fixing this all I was thinking was what a stupid loving problem it was

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

lol i just found out in haskell you can do
code:
let 2 + 2 = 5 in 2 + 2
and it returns 5

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

lol i just found out in haskell you can do
code:
let 2 + 2 = 5 in 2 + 2
and it returns 5

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

thanks radium. thadium.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

fart simpson posted:

lol i just found out in haskell you can do
code:
let 2 + 2 = 5 in 2 + 2
and it returns 5

I wonder if this is a natural consequence of how lazy evaluation was implemented or someone went out of their way to guarantee this is a thing in the language

MeruFM
Jul 27, 2010
most weird syntax issues are fixed with lightweight linters
Especially languages as rigid as python

hell even jshint fixes 99% of javascript problems

Soricidus
Oct 21, 2010
freedom-hating statist shill

Symbolic Butt posted:

I wonder if this is a natural consequence of how lazy evaluation was implemented or someone went out of their way to guarantee this is a thing in the language

neither, it's a consequence of the syntax for function definitions and pattern matching

what "let 2 + 2 = 5" actually does in haskell is create a new infix operator "+" which is only defined for the arguments 2 and 2. this becomes clear if you try "let 2 + 2 = 5 in 1 + 1", which fails with a "non-exhaustive patterns" error.

qntm
Jun 17, 2009

Soricidus posted:

neither, it's a consequence of the syntax for function definitions and pattern matching

what "let 2 + 2 = 5" actually does in haskell is create a new infix operator "+" which is only defined for the arguments 2 and 2. this becomes clear if you try "let 2 + 2 = 5 in 1 + 1", which fails with a "non-exhaustive patterns" error.

does the infix operator "+" already exist in haskell? because if it does, that's insane, whereas if it doesn't, that's insane

Soricidus
Oct 21, 2010
freedom-hating statist shill
it does, but i guess you can redefine it

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Soricidus posted:

neither, it's a consequence of the syntax for function definitions and pattern matching

what "let 2 + 2 = 5" actually does in haskell is create a new infix operator "+" which is only defined for the arguments 2 and 2. this becomes clear if you try "let 2 + 2 = 5 in 1 + 1", which fails with a "non-exhaustive patterns" error.

ooohhh thanks, suddenly I feel like I know everything about haskell now

Soricidus posted:

it does, but i guess you can redefine it

it seems more like it's shadowing the previous definition

gonadic io
Feb 16, 2011

>>=

qntm posted:

does the infix operator "+" already exist in haskell? because if it does, that's insane, whereas if it doesn't, that's insane

Local bindings silently shadow globals while they're in scope

distortion park
Apr 25, 2011


Just got given a bunch of specs for new features and saw a line at the bottom: "Clients may require some changes once they have [these features]". They haven't even talked to real users about what they need.

Jerry Bindle
May 16, 2003
changes are normal right? or does that mean "Clients may decide they want to change the spec they just handed you after you've implemented it, causing you to redo all the work you just did"

Captain Foo
May 11, 2004

we vibin'
we slidin'
we breathin'
we dyin'

MononcQc posted:

A way to organize this one that's interesting is to make it fully asynchronous by sending all player and server actions to a process that acts like an event sync (it can store them transient or permanently if you want game logs).

The game server and all player middlemen processes subscribe to the event sync and write to it.

So the way to think about this one is to have the main server that's a big state machine transitioning between day -> night, during the day phase it receives votes from players and tallies them. It can then transition to night on getting the right vote count (and inserts a message about it to players), triggers the scum actions in the same way, and so on. The thing can just wait for votes from players it has in a list with their status.

Meanwhile the players can subscribe to these events too, relay them to actual human players, and filter stuff in according to the time of the day related by the server, and filter out according to which events the player is allowed to see.

This ends up being a bunch of independently set state machines communicating over messages, but the player process has nearly nothing to know about game mechanics, and can even be used to trigger default actions or route to an AI if you wanted to.


I think this is what I'm planning to do - there are going to be no human players ( I would just run a game if I wanted that ;) ) but to simulate the game of forums Mafia. So I will definitely want detailed logging, so I can report on the results of the game and the actions within.

code:
multiple player processes<---->Event Sync<---->Game Moderator Server
                                   |
                                   v
                                  logfile
is this the basic architecture you're describing?

MononcQc
May 29, 2007

Captain Foo posted:

I think this is what I'm planning to do - there are going to be no human players ( I would just run a game if I wanted that ;) ) but to simulate the game of forums Mafia. So I will definitely want detailed logging, so I can report on the results of the game and the actions within.

code:
multiple player processes<---->Event Sync<---->Game Moderator Server
                                   |
                                   v
                                  logfile
is this the basic architecture you're describing?

Pretty much. This is doable with a gen_event where all the event handlers are more or less filter functions that then forward relevant events to the process that added it. So the game server might subscribe to all events not submitted by the game server, a player may filter for only events targeted to it by the game server or events broadcasted to all possible listeners, and the logfile would subscribe to absolutely everything.

This sets up a workable way to do things, but commits you to a few things, such as having no redundancy for a game process (if the event sync goes, you're done), and developing everything extremely asynchronously. This means you'd have rather tricky integration tests to make sure all players and the game can only switch states in lockstep and won't mess each other up if a message is delayed, for example.

Writing good tests for that is challenging, and usually they will be very superficial. Anything in great depth regarding these tests will require a tool like QuickCheck or PropEr (free variant). These last two will let you establish a model to compare the actions of your program with, and then sets of commands with pre- and post-conditions, and will then generate random walks through your game state, hoping to show that your software matches your model.

It's a more advanced topic and there are tutorials out there for it, but it's usually a far more advanced topic so I'd avoid looking into it until you feel you really need it.

Captain Foo
May 11, 2004

we vibin'
we slidin'
we breathin'
we dyin'

MononcQc posted:

Pretty much. This is doable with a gen_event where all the event handlers are more or less filter functions that then forward relevant events to the process that added it. So the game server might subscribe to all events not submitted by the game server, a player may filter for only events targeted to it by the game server or events broadcasted to all possible listeners, and the logfile would subscribe to absolutely everything.

This sets up a workable way to do things, but commits you to a few things, such as having no redundancy for a game process (if the event sync goes, you're done), and developing everything extremely asynchronously. This means you'd have rather tricky integration tests to make sure all players and the game can only switch states in lockstep and won't mess each other up if a message is delayed, for example.

Writing good tests for that is challenging, and usually they will be very superficial. Anything in great depth regarding these tests will require a tool like QuickCheck or PropEr (free variant). These last two will let you establish a model to compare the actions of your program with, and then sets of commands with pre- and post-conditions, and will then generate random walks through your game state, hoping to show that your software matches your model.

It's a more advanced topic and there are tutorials out there for it, but it's usually a far more advanced topic so I'd avoid looking into it until you feel you really need it.

Thanks for all the insight - this is all going to be run locally, and it's utterly non-critical so I think I'll work on the design of the basic model as you described the first paragraph. On the actual practical side of things, I've built a function to slurp a player list from disk and then return a random selection of ?GAMESIZE players :)

CPColin
Sep 9, 2003

Big ol' smile.
We're integrating some PayPal functionality at work. The "everybody is configured correctly" case is working fine, but we have no idea what'll happen when stuff fails, because PayPal's documentation is poo poo. I'm about to advocate that we should release like this and just leave room in our project planning for the inevitable emergency patches.

Ugh.

VikingofRock
Aug 24, 2008




gonadic io posted:

Local bindings silently shadow globals while they're in scope

To expand on this, that new definition of the + operator only exists in the expression following "in"--so in practice it is very local. If you try to define a new + function on a more global scope you can, but you have to specify which + function you are using from then on:

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.

Barnyard Protein posted:

changes are normal right? or does that mean "Clients may decide they want to change the spec they just handed you after you've implemented it, causing you to redo all the work you just did"

This is pretty much why for my little dev/design shop we don't quote, we estimate and give them a budget of hours to work with.

Because getting them to be happy with committing to a spec is nigh on impossible, and were not keen on being left holding the bill because of an overrun on communication or reimplementation.

lord of the files
Sep 4, 2012

comedyblissoption posted:

breaking stuff up into small composable functions is not such an undue burden that 300 line functions are excusable. it's generally easier to write a bunch of small composable functions than the equivalent 300 line function in the first place.

you're completely right that just because you have short functions doesn't mean you have good design. a bunch of contextless short functions that just mutate global (or class) state and have no explicit inputs or outputs is potentially worse than just stuffing all the code into a giant function.

the key here to good design is trying to as much as reasonably possible structure your program as the composition of small, pure or kind-of-pure functions. as much as possible, make the output of a function depend on its inputs. unfortunately a lot of languages kind of work against doing this right and you kind of have to do half-assed pure functions, but it's certainly better than alternatives.

i break longer functions into smaller chunks and try to make smaller methods from them if they get to large. i dont turn a few lines into a function just because, only if they can be called more than twice. sometimes i turn them into functions just to help readability, or if I want to test it in isolation. i agree that sometimes the push for smaller functions makes people think that that means cleaner code, which is not always the case.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
it also depends on the complexity, sometimes the function is way too big but it's all 300 lines of pure drudgework, like say setting up an http request in some lovely C library

so, in the case of this clown circus of a function devoid of any significant logic, it gives you almost zero benefit to break down into smaller functions




but in general I tend to lazily write big functions. having a conscious effort of pushing them into smaller functions when I feel like it never hurted me

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

CPColin posted:

I'm about to advocate that we should release like this and just leave room in our project planning for the inevitable emergency patches.

You should do that anyway.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Nitrocat posted:

i break longer functions into smaller chunks and try to make smaller methods from them if they get to large. i dont turn a few lines into a function just because, only if they can be called more than twice. sometimes i turn them into functions just to help readability, or if I want to test it in isolation. i agree that sometimes the push for smaller functions makes people think that that means cleaner code, which is not always the case.

Sometimes I do break things up even if I'll only call it once, especially if a nicely named function call is going to be more comprehensible than whatever 5-6 lines of code are there. Like, if I have 5 lines of code to retrieve a piece of data from the database and put it into a variable, that can look kinda junky since (horror alert), our database refers to all data elements by numeric IDs. So I might replace something like the following:
code:
... (some code here)
s date = (some function/context array that gives the date I need to look up)
s patient = (some function to get the patient that's being worked with in this context)
s patientInsurance = (function that takes date and patient and uses some other criteria to figure out what insurance is currently affected)
s coveredMeds= (database lookup for list of meds covered from patientInsurance)
s medIsCovered = (search coveredMeds for this med).
with this:
code:
s medIsCovered = $$getMedIsCoveredCurContext(med)
Even though I'll only need to check that the medication is covered one time, it's not immediately obvious why I'm looking up all those other ancillary data items first, and it's made grosser by the syntax for the stuff I handwaved into () because they're proprietary stuff. It also has the advantage that if we ever do end up needing to deal with medication coverage status in another context, the function may be able to be reused with minor modifications. Without a cleanly labelled function, someone may never have found the chunk of code I used to do it and will end up engineering a different solution (either better or worse) without showing me, which is bad either way.

distortion park
Apr 25, 2011


Barnyard Protein posted:

changes are normal right? or does that mean "Clients may decide they want to change the spec they just handed you after you've implemented it, causing you to redo all the work you just did"

they haven't even spoken to clients about the spec. they're just guessing at what they want it's ridiculous

Jerry Bindle
May 16, 2003

pointsofdata posted:

they haven't even spoken to clients about the spec. they're just guessing at what they want it's ridiculous

do... we work together?

Shaggar
Apr 26, 2006
lol just now learning about yield return.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Shaggar posted:

lol just now learning about yield return.

dude, yield return owns. how did you not know about yield return.

do you know about adding indexers to collections that aren't otherwise accessible using [] syntax?

Shaggar
Apr 26, 2006
idk never came up until today.

ive added [] overloads to stuff before but im not sure if that's what you mean.

AWWNAW
Dec 30, 2008

Shaggar posted:

lol just now learning about yield return.

don't get to crazy with it, especially when you don't really need deferred execution or when you know exactly how many items you're going to be returning anyway. it's nice not having to define a variable to hold your yielded results but it doesn't come for free

Adbot
ADBOT LOVES YOU

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Shaggar posted:


ive added [] overloads to stuff before but im not sure if that's what you mean.

Yeah, I mean that. It blew my mind when I first learned it, because it meant you could do things like overload [] on a dictionary or something to use array-like syntax to look up dictionary items, and the like. It's not always insanely useful, but it makes me obnoxiously happy for some reason.

  • Locked thread