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.
 
  • Post
  • Reply
DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Puella Magissima posted:

A while ago I wrote a bash script to print mpd's currently playing song and status. For most songs it works fine, but today I played a song with a * in it and the script printed the contents of my home directory. I don't know if bash is the horror or if I'm the horror for using it even for lovely one-off scripts. Probably both.

Heh, my first program that did something cool was a bash script that pulled my library from mpd and injected it into the right-click desktop menu (I think it just generated XML files that openbox used to produce pipe menus).

Wish i still had that somewhere.

Adbot
ADBOT LOVES YOU

necrotic
Aug 2, 2005
I owe my brother big time for this!

MALE SHOEGAZE posted:

Heh, my first program that did something cool was a bash script that pulled my library from mpd and injected it into the right-click desktop menu (I think it just generated XML files that openbox used to produce pipe menus).

That sounds like a horrible way to browse your music.

xzzy
Mar 5, 2009

Sounds better than my first mp3 organizer.. 1999, everyone at work was downloading every single song off Napster and putting it on a shared server. I built some cgi scripts (in perl) that printed a checkbox for each directory to allow you to select which collections you wanted. Hit submit, it built an m3u file. Open it in winamp and presto, music.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

necrotic posted:

That sounds like a horrible way to browse your music.

It sure was!!




And now you can try it yourself.

code:
#!/bin/bash
## $1 is current command, $2 is current artist, $3 is current album, $4 is current song


##newlist()
## After md5sum check fails, parse a new list to be read for menu items
#{

parse ()
{
md51=`mpc -f "[zXz%artist%zXz%album%zXz%title%]" playlist|md5sum|cut -c -32`
md52=`tail -1 /tmp/.albumparse|cut -d ":" -f10`
if [ "$md51" != "$md52" ]
	then
INIT_TAB_AWK=""
mpc -f "[zXz%artist%zXz%album%zXz%title%]" playlist|sed -e 's/(//g' | sed -e 's/)//g' | sed -e 's/\#//g' | sed -e 's/\,//g'| sed -e 's/\&/&/g'| sed -e 's/\://g'|awk -F zXz '{printf ":%s:%s:%s:%d\n",$2,$3,$4,$1}'|


awk -F: '
{ $INIT_TAB_AWK }

{c++;r++}
{if ($2 != a) i++}
{if ($3 != b) p++ && r=1}
{if ($3 !=b && $2 != a) p = 1}
{printf ("%d:%d:%d:%s:%s:%s:%d\n",i,p,r,$2,$3,$4,c)}
{b = $3}
{a = $2}

' > /tmp/.albumparse
mpc -f "[zXz%artist%zXz%album%zXz%title%]" playlist|md5sum|cut -c -32|awk '{printf ":::::::::%s",$1}' >> /tmp/.albumparse
fi

}


getinfo()
{
# when parsing, total artists = $1, total albums = $2, total songs = $3, artist name = $4, album = $5, song 
# = $6


	if [ "$1" = getalbums ]
	then	
 	echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
	echo "<openbox_pipe_menu>"
		
	n="$2"
	i=`awk -F: -v n=$n '$1 == n {print $2}' /tmp/.albumparse|uniq|wc -l`
	p=`awk -F: -v n=$n '$1 == n && $3 == 1 {print $2}' /tmp/.albumparse|head -1|tail -1`
	for ((m=1;m<=$i;m++))
	do
	
	albumname=`awk -F: -v z=$m -v n=$n '$1 == n && $2 == z && $3 == 1 {print $5}' /tmp/.albumparse`
	echo "<menu id=\"album$n$m\" label=\"$albumname\" execute=\"mpdmenu2.sh 'getsongs' '$n' '$m'\" />"
	##echo "<menu id=\"artist$m\" label=\"$artistname\" execute=\"mpdmenu2.sh 'getartist' $m\" />"

	#done

	echo

	done
	echo "</openbox_pipe_menu>"

	fi  
	
## make list of songs within an album. $1 is "Getsongs" command, $2 is artist #, $3 is song #
	if [ "$1" = getsongs ]
		then	
 		echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
		echo "<openbox_pipe_menu>"
	# define n as artist number, s as album number	
		s="$3"	
		n="$2"
	# i represents total number of songs on album, number of times to run loop
		i=`awk -F: -v n=$n -v s=$s '$1 == n && $2 == s {print $3}' /tmp/.albumparse|wc -l`
	
		songnumber=`awk -F: -v s=$s -v m=1 -v n=$n '$1 == n && $2 == s && $3 == m {print $7}' /tmp/.albumparse|head -1|tail -1`
			
		for ((m=1;m<=$i;m++))
		do
		songname=`awk -F: -v s=$s -v m=$m -v n=$n '$1 == n && $2 == s && $3 == m {print $6}' /tmp/.albumparse`
		
		echo "<item label=\"$songname\"> <action name=\"Execute\"><command>mpc play $songnumber</command></action></item>" 
		songnumber=$((songnumber+1))		
			
		done
   	echo "</openbox_pipe_menu>"	
fi

#echo "get info"



#echo "got info"
# passed from command line in script execution,
# for awk, $1 is songcount, $2 is startline, $3 is artist, $4 is album 
# will pass information from command line as
#  $1 operation to perform, $2 current artist, $3 current album 






}
makeartist ()
{


	totalartists=`tail -2 /tmp/.albumparse|head -1|cut -d ":" -f1` 
	i="$totalartists"
	echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
	echo "<openbox_pipe_menu>"
	for ((m=1;m<=$i;m++))
	do
	artistname=`awk -F: -v n=$m '$1 == n && $3 == 1 {print $4}' /tmp/.albumparse|head -1|tail -1`
	echo "<menu id=\"artist$m\" label=\"$artistname\" execute=\"mpdmenu2.sh 'getalbums' '$m'\" />"

	done

	echo "</openbox_pipe_menu>"

}
getalbums()
{
#  $1 is "getalbums" command, $2 is "$i", the artist number
getinfo "$1" "$2" "$3"


}
#getsongs "$1" "$2" "$3"
controlpanel()
{

echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
echo "  <item label=\"MPC Prev\">"
echo "    <action name=\"Execute\"><command>mpc prev</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Play\">"
echo "    <action name=\"Execute\"><command>mpc play</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Pause\">"
echo "    <action name=\"Execute\"><command>mpc pause</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Stop\">"
echo "    <action name=\"Execute\"><command>mpc stop</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Next\">"
echo "    <action name=\"Execute\"><command>mpc next</command></action>"
echo "  </item>"

echo "</openbox_pipe_menu>"
}



volume()
	{

echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
echo "  <item label=\"100%\">"
echo "    <action name=\"Execute\"><command>mpc volume 100</command></action>"
echo "  </item>"
echo "  <item label=\"90%\">"
echo "    <action name=\"Execute\"><command>mpc volume 90</command></action>"
echo "  </item>"
echo "  <item label=\"80%\">"
echo "    <action name=\"Execute\"><command>mpc volume 80</command></action>"
echo "  </item>"
echo "  <item label=\"70%\">"
echo "    <action name=\"Execute\"><command>mpc volume 70</command></action>"
echo "  </item>"
echo "  <item label=\"60%\">"
echo "    <action name=\"Execute\"><command>mpc volume 60</command></action>"
echo "  </item>"
echo "  <item label=\"50%\">"
echo "    <action name=\"Execute\"><command>mpc volume 50</command></action>"
echo "  </item>"
echo "  <item label=\"40%\">"
echo "    <action name=\"Execute\"><command>mpc volume 40</command></action>"
echo "  </item>"
echo "  <item label=\"30%\">"
echo "    <action name=\"Execute\"><command>mpc volume 30</command></action>"
echo "  </item>"
echo "  <item label=\"20%\">"
echo "    <action name=\"Execute\"><command>mpc volume 20</command></action>"
echo "  </item>"
echo "  <item label=\"10%\">"
echo "    <action name=\"Execute\"><command>mpc volume 10</command></action>"
echo " </item>"
echo "  <item label=\"Mute\">"
echo "    <action name=\"Execute\"><command>mpc volume 0</command></action>"
echo "  </item>"
echo "</openbox_pipe_menu>"
}


settings()
{
repeatstatus=`mpc | tail -1 | awk -F"   " '{print $2}'| sed 's/r/R/'|sed 's/o/O/'`
randomstatus=`mpc | tail -1 | awk -F"   " '{print $3}'| cut -d ":" -f2 |cut -c 2-| sed 's/o/O/'`

echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
echo "  <item label=\"MPC Prev\">"
echo "    <action name=\"Execute\"><command>mpc prev</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Play\">"
echo "    <action name=\"Execute\"><command>mpc play</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Pause\">"
echo "    <action name=\"Execute\"><command>mpc pause</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Stop\">"
echo "    <action name=\"Execute\"><command>mpc stop</command></action>"
echo "  </item>"
echo "  <item label=\"MPC Next\">"
echo "    <action name=\"Execute\"><command>mpc next</command></action>"
echo "  </item>"
echo " <separator />"
echo "  <item label=\"$repeatstatus\">"
echo "    <action name=\"Execute\"><command>mpc repeat</command></action>"
echo "  </item>"
echo "  <item label=\"Random: $randomstatus\">"
echo "    <action name=\"Execute\"><command>mpc random</command></action>"
echo "  </item>"
echo "  <item label=\"Launch MPC\">"
echo "   <action name=\"Execute\"><command>urxvt -e \"ncmpcpp\"</command></action>"
echo "  </item>"
echo "<menu id=\"Volume\" label=\"Volume\" execute=\"mpdmenu2.sh 'volume'\" />"  
echo "</openbox_pipe_menu>"
}

playlists ()
{
playlistcount=`awk '{print $1}' "/tmp/.mpdplaylistsmenu"|wc -l`
playlistnames=`awk '{print $1}' "/tmp/.mpdplaylistsmenu"`
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
for ((playlistcurrent=1; playlistcurrent <= $playlistcount; playlistcurrent ++))
do 
playlistname=`echo "$playlistnames"|head -$playlistcurrent|tail -1`
echo "<item label=\"$playlistname\"><action name=\"Execute\"><command>mpc clear</command></action><action name=\"Execute\"><command>mpc load '$playlistname'</command></action></item>"
done
echo "</openbox_pipe_menu>"
}

mainmenu ()
{
parse
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
nowartist=`mpc current -f %artist% | sed -e 's/\&/&amp;/g'`
nowsong=`mpc current -f %title% | sed -e 's/\&/&amp;/g'`
nowalbum=`mpc current -f %album% | sed -e 's/\&/&amp;/g'`

nowstatus=`mpc -f f | awk '{print$1}'|head -n 2|tail -1 | sed 's/\]//' | sed 's/\[//'| sed 's/p/P/'`
nowtime=`mpc -f f | awk '{print$3}'|head -n 2|tail -1` 
echo " <separator label=\"$nowsong\" />"
echo " <separator label=\"$nowartist - $nowalbum\" />"
echo "<item label=\"$nowstatus - $nowtime\"><action name=\"Execute\"><command>mpc toggle</command></action></item>"
echo " <separator />"

echo " <menu id=\"playlistmenu\" label=\"Playlists\" execute=\"mpdmenu2.sh 'playlists'\" />"

echo " <menu id=\"artistmenu\" label=\"Artists\" execute=\"mpdmenu2.sh 'getartist'\" />"  
	
echo " <menu id=\"controlmainmenu\" label=\"Control Panel\" execute=\"mpdmenu2.sh 'settings'\" />"  


echo "</openbox_pipe_menu>"

#for ((currentartist=1; currentartist < $artistcount; currentartist++))
#do
#done

}
if [ -z "$1" ]
then
mainmenu
fi

if [ "$1" = getartist ]
then	
   makeartist "$1" "$2" "$3"
fi

	if [ "$1" = getalbums ]
	then
   	getalbums "$1" $2 "$3"
	fi
	
		if [ "$1" = getsongs ]
		then
		getinfo "$1" "$2" "$3"
		
		
		fi
	

		if [ "$1" = settings ]
		then
		settings
		
		
		fi
	
		if [ "$1" = playlists ]
		then
		playlists
		
		
		fi
	
Apparently I was so proud of this that I emailed it to my friend.

DONT THREAD ON ME fucked around with this message at 02:38 on Oct 8, 2015

Rigged Death Trap
Feb 13, 2012

BEEP BEEP BEEP BEEP

Ooh
Is there anyway to transform the menu, so the position doesnt change but the size and content does?


fake edit: i.e: iPod style menu traversal.

Carbon dioxide
Oct 9, 2012

Weird little HTML thing...

Why does html think chucknorris is a color?

xzzy
Mar 5, 2009

That's not a horror, that's awesome.

karms
Jan 22, 2006

by Nyc_Tattoo
Yam Slacker
Then why does #rebeccapurple gives us purple?

ToxicFrog
Apr 26, 2008


xzzy posted:

Shell has always been a minefield of quote and escape errors.

code:
system("du -sh \"" ARGV[3] ARGV[4] \\\$0 "\" | awk \\\"{ print \\\\\\\\\\$1 }\\\"");
This was part of a CGI file manager written in bash. I think it was responsible for displaying file/directory sizes.

Carbon dioxide
Oct 9, 2012

What actually happens, according to the answers on that page, is that all characters that aren't hex digits are replaced by zeroes, then zeroes are appended until the number of chars can be divided by three, then the string is divided in three groups, and each group is read as a hex code for R, G, and B.

Depressing Box
Jun 27, 2010

Half-price sideshow.

KARMA! posted:

Then why does #rebeccapurple gives us purple?

In memory of Eric Meyer's daughter.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

Appropriate username/post combo :(

ChickenWing
Jul 22, 2010

:v:

It's me, I'm the horror :cripes:


A couple months ago I was assigned to work on a mapper and I cried a little inside because it was awful hacky garbage. However, as an intern, I didn't want to step on any toes to I tiptoed around the awful hacky garbage the best I could and managed to complete my addition.


Now that we're testing with appropriate amounts of test data, our frontend guys are unhappy with how the data is being presented and need it condensed a little. In the intervening period, I'd completely forgotten about this soggy mess of spaghetti code (this was actually my first encounter in the wild with using strings as :airquote:data structures:airquote:, before I thought it was something no self-respecting programming-employed person would do). Now I have to dig back in and smash together some stuff that is fundamentally opposed to being smashed together. The best part is that we're now in SIT, so an aggressive refactor is pretty much off the table.



:negative:

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
We're well under way taking over the operations of another company - we're a small company but the company we're taking over is smaller still (3 people who are now retiring). We keep running across funny and/or frustrating things they have done in their code. An example would be one of their internal tools which when we first got the code, would check at startup whether there's a folder in the C: drive called "hp" and vary its behaviour accordingly - presumably because one of the people who used it has an HP laptop and the other doesn't.

necrotic
Aug 2, 2005
I owe my brother big time for this!

xzzy posted:

Sounds better than my first mp3 organizer.. 1999, everyone at work was downloading every single song off Napster and putting it on a shared server. I built some cgi scripts (in perl) that printed a checkbox for each directory to allow you to select which collections you wanted. Hit submit, it built an m3u file. Open it in winamp and presto, music.

At least with that if you misclick you don't close the entire thing and have to start browsing from the ground floor again.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer
Hey y'all. I finally got my full-time developer position and a 50% raise to go with it. Thanks for teaching me cool things while I went through my journey of becoming a coding horror creator, horrors thread.

edit: Hah, I found the source to my awful turbopascal text adventure that I wrote in high school. Have it as a gift to the coding horrors thread:

LeftistMuslimObama posted:

I dug up the "text adventure" I wrote in TurboPascal in 10th grade. I didn't know anything about non-array data structures or about loading from/saving to files so the entire game map is encoded as several hundred methods. Each method does the following:
1)Print a description of where you're standing
2)Perform a random number generation to determine if you are attacked by a monster, initiate battle engine if so.
3)State which directions you can go in, prompt for input.

Each method then simply called the method that represented the "cell" in the direction you wanted to go in. The map was close to 500x500 cells (I drew it in Excel to use as a reference while I coded). Also no validation of any input at any point. I spend close to 50 hours over thanksgiving weekend coding the stupid thing, and the file got so big that I exceeded the maximum line count TurboPascal for Windows could handle and had to switch to Borlean's shareware DOS pascal IDE (I hadn't learned about header files yet either).

http://pastebin.com/Qvg91WBn

The MUMPSorceress fucked around with this message at 21:34 on Oct 9, 2015

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



"You're welcome, Obama"

Wait, that's not right

Zorro KingOfEngland
May 7, 2008

code:
writeln ('tis not a real letter fool!');
Stealing this for my next validation error message.

also this
code:
writeln ('thou art not even typing proper letters moron!');

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer
Lol. I have a writing degree now too. 10th grade me was, uh, creative...

KaneTW
Dec 2, 2011

Node.js. That is all.

YO MAMA HEAD
Sep 11, 2007

LeftistMuslimObama posted:

Lol. I have a writing degree now too. 10th grade me was, uh, creative...

I especially like the way you apparently started out trying to write unique error messages for each location but ended up just using that one 300 times

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

YO MAMA HEAD posted:

I especially like the way you apparently started out trying to write unique error messages for each location but ended up just using that one 300 times

I coded it all by hand every time too. Not so much as a copy and paste. I'm not even that dedicated to stuff I get paid for now.

FieryBalrog
Apr 7, 2010
Grimey Drawer
This may be a coding horror but I was reading the last page and I vastly prefer code like this

code:
    @Override
    public boolean equals(Object o) {
        if (o == this) 
          return true;

        if (o instanceof Coordinate) {
            Coordinate c = (Coordinate)o;
            if (c.x() == x && c.y() == y)
              return true;
        }
      return false;
    }
This amounts to:
if (1), return true.
if (2), then if (3), return true.
by default return false.

Which seems extremely readable to me.

Most of the time it makes my eyes twitch if I would have to instantiate an arbitrary local boolean - sometimes multiple, depending on the desire to exit for-loops- and then make that boolean jump through the same hoops that the returns do before returning the state, all for the sake of treating "single exit only" like a Biblical Commandment.

If people couldn't follow the (extremely straightforward) branching of multiple returns then following the state of a local variable as it follows the same branches is not easier, it's harder. Especially true when it involves terminating loops early.

Of course there are exceptions to this too, if instantiating said booleans or local state variables does make the program easier to read.

FieryBalrog fucked around with this message at 21:28 on Oct 10, 2015

Xarn
Jun 26, 2015

FieryBalrog posted:

This may be a coding horror but I was reading the last page and I vastly prefer code like this

code:
    @Override
    public boolean equals(Object o) {
        if (o == this) 
          return true;

        if (o instanceof Coordinate) {
            Coordinate c = (Coordinate)o;
            if (c.x() == x && c.y() == y)
              return true;
        }
      return false;
    }

You are the worst kind of scum if you write code like this.

(Put in the goddamn braces)

brap
Aug 23, 2004

Grimey Drawer
Early returns are preferable to mutation. I feel like I may have posted this exact statement here before.

Corla Plankun
May 8, 2007

improve the lives of everyone
I like using ifs without braces when it is for simple stuff like return true, but idk why people don't make them one-liners.

If it is already taking up two lines you might as well add the brackets.

loinburger
Jul 10, 2004
Sweet Sauce Jones
I'm writing the back end for a job scheduler; previously we could only execute one instance of a job at a time because the jobs used stored procedures that had temp state and weren't safe to call concurrently, but the database people fixed this and now it's possible for us to concurrently execute multiple instances of the same job type. This means that the return types for a few REST calls have to change, e.g. /status/jobtype used to return a single JobStatus (converted to JSON) but now needs to return a List<JobStatus> since multiple jobs of that type might be running.

In an attempt to not have to do any work, the front end guy is saying that we just shouldn't tell the user that we can execute multiple jobs concurrently - that way we can keep returning a single JobStatus, the front end guy doesn't need to change any of his poo poo, and the user won't realize that they ought to be receiving a List<JobStatus>.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

fleshweasel posted:

Early returns are preferable to mutation. I feel like I may have posted this exact statement here before.

You were right then, you're right now.

Corla Plankun posted:

I like using ifs without braces when it is for simple stuff like return true, but idk why people don't make them one-liners.

If it is already taking up two lines you might as well add the brackets.

One-line conditional flow control has no place in source code that will be read again in the future. Flow control is important, give it space and make it easier to read.

NihilCredo
Jun 6, 2011

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

So, I gather that the perfect version of this code should have no mutation, a single return statement, and two braces for every if block.

Well, the solution seems blindingly obvious to me. I don't know, maybe you're all bad? :confused:

code:
    @Override
    public boolean equals(Object o) {
        return ((o == this) || ((o instanceof Coordinate) && ((Coordinate)o.x() == x) && ((Coordinate)o.y() == y)));
    }

dc3k
Feb 18, 2003

what.

NihilCredo posted:

So, I gather that the perfect version of this code should have no mutation, a single return statement, and two braces for every if block.

Well, the solution seems blindingly obvious to me. I don't know, maybe you're all bad? :confused:


i hate you

Polio Vax Scene
Apr 5, 2009



For some reason the x() and y() being functions is what frustrates me most.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Manslaughter posted:

For some reason the x() and y() being functions is what frustrates me most.

That's just standard C++.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

loinburger posted:

I'm writing the back end for a job scheduler; previously we could only execute one instance of a job at a time because the jobs used stored procedures that had temp state and weren't safe to call concurrently, but the database people fixed this and now it's possible for us to concurrently execute multiple instances of the same job type. This means that the return types for a few REST calls have to change, e.g. /status/jobtype used to return a single JobStatus (converted to JSON) but now needs to return a List<JobStatus> since multiple jobs of that type might be running.

In an attempt to not have to do any work, the front end guy is saying that we just shouldn't tell the user that we can execute multiple jobs concurrently - that way we can keep returning a single JobStatus, the front end guy doesn't need to change any of his poo poo, and the user won't realize that they ought to be receiving a List<JobStatus>.

When making a breaking change to an API (and changing the from returning a single value to returning a list of values is definitely something that could break consumers of the API), it's often better to simply deprecate the old API and introduce a new version that behaves how you want it to behave.

raminasi
Jan 25, 2005

a last drink with no ice

NihilCredo posted:

So, I gather that the perfect version of this code should have no mutation, a single return statement, and two braces for every if block.

Well, the solution seems blindingly obvious to me. I don't know, maybe you're all bad? :confused:

code:
    @Override
    public boolean equals(Object o) {
        return ((o == this) || ((o instanceof Coordinate) && ((Coordinate)o.x() == x) && ((Coordinate)o.y() == y)));
    }

I think that's perfectly readable if you break it up into multiple lines.

FieryBalrog
Apr 7, 2010
Grimey Drawer
I agree, x() and y() seem dumb. "Coordinate" is a class I wrote within the first month of me learning Java (also my first programming language), and the reason for x() and y() is:

me: getters and setters seem really superfluous a lot of the time. But everyone says I should use them all the time. So let me make getX() and setX(). Oh wait, it's really annoying to type getX and setX all the time. Also Joshua Bloch says immutable classes are better and this seems like a class that should be immutable. So let me make x and y final and get rid of these setters. getX() is still annoying to type but everyone says I should have getters. Fine so let me just make the getter as concise as it could possibly be.

Maybe I'm wrong and this isn't dumb and I should keep the getters here instead of making it public final int, but I don't know what the right answer is.

FieryBalrog fucked around with this message at 02:24 on Oct 13, 2015

Bongo Bill
Jan 17, 2012

C# properties are what you want. Java does not have syntax for them. Just use getters and setters. You'll get used to it.

ullerrm
Dec 31, 2012

Oh, the network slogan is true -- "watch FOX and be damned for all eternity!"

Having a compiler keyword to say "synthesize getters/setters for this member variable, and while you're at it, optionally generate code for atomic accesses, weak reference gets, etc" is one of the few things that Objective-C got right.

(And then I remember the last year of dealing with Apple's "burn the ships" approach to reverse compatibility, and the abomination that is NSMutableString, and I want to cry and never code in it again.)

FieryBalrog
Apr 7, 2010
Grimey Drawer
I guess I like this guy's answer on why getters and setters don't always make sense instead of just having public fields:

http://stackoverflow.com/a/12108025/2022797

This is sort of my thought process. I don't think the getter SHOULD ever change the way this field is returned or used, so using a getter is, if anything, misleading compared to just having people use the public (and final) int value. Also the getter can be subclassed and overridden and I don't think that's a plus either. I didn't make Coordinate final because I made subclasses of it that had additional state and behavior (like a subclass where you could define connections to other coordinates).

FieryBalrog fucked around with this message at 02:57 on Oct 13, 2015

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
That guys argument is basically "if you want to change something, you should be forced to also change everything that depends on what you changed", which really isn't how sustainable software development works. Often you want to extend your class with new functionality and fields, which requires validating that the newly-added field doesn't conflict with any older ones. You might want to add callbacks that notify something else when a field is changed. You might want to start caching derived properties instead of recomputing them all the time, and need to know when to invalidate that cache. You might want to change which of your properties are actually stored directly, and which ones are derived from the stored properties. All of these are (more frequent than you think) changes that don't affect the external semantics of the class (at least as far as any previously-written code understands them), and shouldn't require wide-ranging yet mechanical changes to everything that uses it. This is especially important when you start producing code that's used by other people, where it might be literally impossible for you to just go in and change their code, and instead requires them to do the pointless busywork when you need to turn a field into a getter/setter pair.

I have written dumb data holders that just use fields rather than getter/setters, but those have always been internally-scoped (usually private inner classes), which limits the scale of how much you need to refactor when your initial assumptions change.

Adbot
ADBOT LOVES YOU

Linear Zoetrope
Nov 28, 2011

A hero must cook
I don't really use C#, but isn't that what structs are usually for in that language? I always thought it was customary to use getters/setters for classes and structs for dumb data blobs with public fields.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply