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
Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Thermopyle posted:

Isn't it as wide as it is tall? I mean, the dict-like nature seen in "save" is just an artifact of using shelve.

Forget about shelve. Pretend the contents of "save" is code for writing results to a MySQL database.

The question is more about coding style and less about shelve.
The key reason why save() is unnessesary is that def save(obj): shelf[obj.name] = obj doesn't abstract much of anything. Assuming you are writing the MySQL-based persistence layer, if you changed the global variable name from shelf to something along the lines of persistenceobject, there is no situation where you would have to change the body of save and nothing else. It is no more difficult to write a MySQL-based persistence layer that uses __getitem__ and __setitem__ than one which has the exact same methods named get and save (or whatever you prefer).

The class obj(): def save(self): shelf[self.name] = self version actually does do something interesting, as it gives objects control over how they're persisted. However, if def save(obj): shelf[obj.name] = obj was ever actually useful, then it should actually be class obj(): def save(self): save(self.name, self), as having to modify every class that can be persisted when you change persistence layers is almost as bad as having to change every place where an object is saved.

Adbot
ADBOT LOVES YOU

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Plorkyeran posted:

The class obj(): def save(self): shelf[self.name] = self version actually does do something interesting, as it gives objects control over how they're persisted. However, if def save(obj): shelf[obj.name] = obj was ever actually useful, then it should actually be class obj(): def save(self): save(self.name, self), as having to modify every class that can be persisted when you change persistence layers is almost as bad as having to change every place where an object is saved.

In Stack Overflow style, I mark this as the accepted answer. :D

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

Avenging Dentist posted:

There's a world of difference between "we do not accept optimization patches" and "we do not devote our effort to making optimizations". If, however, the primary project you work with is Python, then I can see why you'd think they're not optimization-unfriendly.

We do accept optimization patches. Anyone is welcome to submit one, and most have a very high chance of getting committed if there is an owner for the space that the patch is in, who is attentive. The fact is, we accept them, but there are very few people focused on re-architecting and doing optimizations on the interpreter itself. The most recent of those people are Antoine, who did a pretty major change to the way the GIL works within Py3k (for the better). Most of the work day-to-day is no where near the interpreter internals. We simply don't have someone who "wants" to do that, or has the time.

What I got pissed about was this:

quote:

CPython is one of the least optimization-friendly projects I've seen. Most of the Python community seems to think that CPython is already fast enough, even though the performance is often downright sad.

I don't see us (us being python-core) as being optimization "unfriendly" - if you're saying it's not easy to optimize certain things due to the CPython implementation, then yes - the core implementation needs work (see unladen-swallow and king_kilr's comments). If you mean socially - then no, a patch is a patch to us. If it's clean, follow guidelines, and doesn't hamstring backwards compatibility, C extensions, etc - then there's a good chance it'll get in.

As for the community - you have to understand that Python, for many people is a "glue" language, and most of that glue doesn't have to be very perfomant. Their perspective is skewed towards what they do day to day. Those of us building bigger things, which have to have great performance see it in a much different light. This is actually one of the reasons the GIL is still around in it's current form - for those glue programmers/web people who are running in one or two threads, any performance hit from fine grained locking is deemed unacceptable.

It's unfortunate, but the glue-people outnumber the performance-oriented people significantly, but the fact remains, if a patch to speed something up without breaking/slowing everything else down is submitted, it'll go in.

m0nk3yz fucked around with this message at 00:43 on Nov 30, 2009

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

The Red Baron posted:

I think it's more a matter of CPython not being able to escape from the needs of legacy support for C-extensions that are built with certain assumptions in mind (i.e. the main reason the GIL still exists) that might preclude certain optimizations. I'm fairly certain Unladen Swallow would see higher performance results if they didn't bother with essentially emulating the python stack machine in a register-based system due to a need for switching between interpretation and native code execution. These are all uneducated observations I have made, though, so I may be wrong.

I think if unladen swallow could break backwards compatibility we'd see some really interesting stuff, but then, what they released wouldn't be python. The backwards compatibility requirements to keep the ecosystem of C extensions vibrant out there suck, and do hold certain things back. But then again, that ecosystem is a large part of why python is so popular. :(

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

m0nk3yz posted:

I don't see us (us being python-core) as being optimization "unfriendly" - if you're saying it's not easy to optimize certain things due to the CPython implementation, then yes - the core implementation needs work (see unladen-swallow and king_kilr's comments). If you mean socially - then no, a patch is a patch to us. If it's clean, follow guidelines, and doesn't hamstring backwards compatibility, C extensions, etc - then there's a good chance it'll get in.

When you compare the Python list to, say, the Boost list, the differences in prevailing opinion on performance are pretty stark. For Python, performance is something nice to have, but not something worth worrying about if you can't (easily) get it. For a lot of other groups, performance is one of the most important aspects when reviewing a patch/feature and can make or break its submission into the core.

What I'm talking about with "optimization-unfriendliness" would perhaps be better stated as: Python is optimization-reactive (passively accepts patches to speed up an existing thing) rather than optimization-proactive (makes things fast to begin with and/or designs the core to ensure that later changes won't be slower than absolutely necessary).

Since the only things I care about in Python are 1) speed, and 2) that it be slightly easier (for a physicist) to use than C/C++/Fortran, the camp I sit in should be pretty obvious.

Avenging Dentist fucked around with this message at 00:54 on Nov 30, 2009

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

Avenging Dentist posted:

When you compare the Python list to, say, the Boost list, the differences in prevailing opinion on performance are pretty stark. For Python, performance is something nice to have, but not something worth worrying about if you can't (easily) get it. For a lot of other groups, performance is one of the most important aspects when reviewing a patch/feature and can make or break its submission into the core.

What I'm talking about with "optimization-unfriendliness" would perhaps be better stated as: Python is optimization-reactive (passively accepts patches to speed up an existing thing) rather than optimization-proactive (makes things fast to begin with and/or designs the core to ensure that later changes won't be slower than absolutely necessary).

Since the only things I care about in Python are 1) speed, and 2) that it be slightly easier (for a physicist) to use than C/C++/Fortran, the camp I sit in should be pretty obvious.

That, I can mostly agree with. A part of this I think boils down to a difference in goals *and* personalities. I work with a hard core C guy for example. He's obsessed with performance and optimizations. I take the tact you mention: Does it go as fast as I need it to? Yes. Does memory growth stay at a reasonable size? Yes. I don't go looking for optimizations until I need them, he can't check in code if it's not optimized.

I think that speaks to what you're saying - as a group, I don't think we're searching out/rejecting patches which are not as performant as they could be. If a patch is good, it gets in - we optimize on demand. I don't think that's a problem of unfriendliness though, just priorities. "Get things done" trumps "Go fast" so to speak. This is (obviously) frustrating for people like you who are looking for speed over "a widget which does some wsgi stuff" (stdlib) or "advanced generators" (core syntax).

That all being said though; I think most of us would kill for a more performant implementation - and I know there are things inside the stdlib which need a once-over with the "go faster" stick. My code included.

m0nk3yz fucked around with this message at 01:03 on Nov 30, 2009

wins32767
Mar 16, 2007

I'm having a problem with distributing eggs. On my old OSX workstation, I used to be able to just run python setup.py bdist_egg and and new files that I added (and checked into svn) would magically appear in the resulting egg. On my new Ubuntu workstation, new files aren't getting packaged. From a bit of googling, I've learned that there is a problem getting setuptools to read the .svn/entries file, so that explains why I'm having the problem. However, I really need to be able to distribute eggs before they release a patch. What file do I need to much about with to ensure that I'm getting all my code into the egg?

EDIT: Figured it out. The dist part of distutils uses SOURCES.txt, build seems to use some sort of magic to generate it.

wins32767 fucked around with this message at 02:34 on Dec 1, 2009

fritz
Jul 26, 2003

m0nk3yz posted:

I think if unladen swallow could break backwards compatibility we'd see some really interesting stuff, but then, what they released wouldn't be python.

So it's ok to break backward compatibility with goofy changes like print -> print() but it's not ok in this case.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

fritz posted:

So it's ok to break backward compatibility with goofy changes like print -> print() but it's not ok in this case.

Given that the way Unladen Swallow gets back into core is by piecemeal patches, your comparison is pretty lacking.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

fritz posted:

So it's ok to break backward compatibility with goofy changes like print -> print() but it's not ok in this case.

If you're going to have a release that breaks compatibility anyway, why not standardize one of the core functions?

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

fritz posted:

So it's ok to break backward compatibility with goofy changes like print -> print() but it's not ok in this case.

I find your example lacking. Namely, Py3k is supposed to break backwards compatibility. It's one thing to have a release that's planned to break backwards compatibility, and offer a conversion utility (2to3) to help ease the change, and a whole other thing to "just change poo poo to change poo poo".

Despite what you might think, Python core has a strict backwards compatibility policy - Py3k is the exception to the rule, given that it is meant to fix certain things within the language which can not be fixed easily without breaking backwards compatibility, and also serve as a cleaner language overall, which it does.

Even knowing that Py3k would break backwards compatibility, the changes made were conservative by any measure. The team as a whole resisted a lot of changes they could have made, instead focusing on the core goals, and a select subset of changes. Print was inconsistent, and actually makes sense as a function call.

As for unladen-swallow - there's going to come a time when they're "done" and they will be merged into core wholesale. Collin has long stated that unladen is a branch of CPython - not a fork. A fork can do many things a branch can not, namely breaking things in the name of the fork. A branch has to stay compatible with core, if it ever has a hope of getting merged back in.

nonathlon
Jul 9, 2004
And yet, somehow, now it's my fault ...

wins32767 posted:

I'm having a problem with distributing eggs. On my old OSX workstation, I used to be able to just run python setup.py bdist_egg and and new files that I added (and checked into svn) would magically appear in the resulting egg. On my new Ubuntu workstation, new files aren't getting packaged. From a bit of googling, I've learned that there is a problem getting setuptools to read the .svn/entries file, so that explains why I'm having the problem. However, I really need to be able to distribute eggs before they release a patch. What file do I need to much about with to ensure that I'm getting all my code into the egg?

EDIT: Figured it out. The dist part of distutils uses SOURCES.txt, build seems to use some sort of magic to generate it.

You've solved it already but MANIFEST.in will also do the trick.

Despite all the complaints about setuptools (admittedly mostly about the internals), I've found it mostly well documented and smooth-sailing until a recent spate of quirky problems. Roll-on distribute.

king_kilr
May 25, 2007
setuptools is fundamentally wrong, and distribute isn't fixing the broken IMO. First step is to change setup.py from a big call to setup() to just being a configuration file that happens to be in python, and moving the intstall command to be python -mdistribute install setup.py

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

If I have a sub-object contained in another object, how do I reference attributes of the root object from within the sub-object?

In case that isn't clear:

code:
class root():
    def __init__(self, var):
        self.a_root_attrib = var
        self.a_sub_obj = sub()

class sub():
    def __init__(self):
        self.root_ref = some way of referring to a_root_attrib

foobar = root('bar')
Sorry I'm such a noob.

tripwire
Nov 19, 2004

        ghost flow

Thermopyle posted:

If I have a sub-object contained in another object, how do I reference attributes of the root object from within the sub-object?

In case that isn't clear:

code:
class root():
    def __init__(self, var):
        self.a_root_attrib = var
        self.a_sub_obj = sub()

class sub():
    def __init__(self):
        self.root_ref = some way of referring to a_root_attrib

foobar = root('bar')
Sorry I'm such a noob.
super

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

tripwire posted:

super

No, that's for base classes, not for the owner of an instance.

As for the question, the answer is probably "you didn't design your code very well and should reorganize it."

tripwire
Nov 19, 2004

        ghost flow

Avenging Dentist posted:

No, that's for base classes, not for the owner of an instance.

As for the question, the answer is probably "you didn't design your code very well and should reorganize it."

:doh: You're right again

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Avenging Dentist posted:

No, that's for base classes, not for the owner of an instance.

As for the question, the answer is probably "you didn't design your code very well and should reorganize it."

This is what I was afraid of.

Thanks a lot, jerk.

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

king_kilr posted:

setuptools is fundamentally wrong, and distribute isn't fixing the broken IMO. First step is to change setup.py from a big call to setup() to just being a configuration file that happens to be in python, and moving the intstall command to be python -mdistribute install setup.py

Tarek knows that this is fundamentally broken - the first thing they have to do within distribute though is to make it work in the current ecosystem, then they can start making wider changes.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Thermopyle posted:

This is what I was afraid of.

Thanks a lot, jerk.

Only a jerk would suggest that a programmer be cognizant of a language's limitations when writing software.

king_kilr
May 25, 2007

m0nk3yz posted:

Tarek knows that this is fundamentally broken - the first thing they have to do within distribute though is to make it work in the current ecosystem, then they can start making wider changes.

I know. I should have said "not addressing that *yet*". I'll give Tarek and Jannis all the time they need, but I'm not switching yet.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Avenging Dentist posted:

Only a jerk would suggest that a programmer be cognizant of a language's limitations when writing software.

I can't tell if you understood this or not, but I was joking when I called you a jerk.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Thermopyle posted:

I can't tell if you understood this or not, but I was joking when I called you a jerk.

I figured. The post was as much for the benefit of others as it was for you (lots of people seriously do think that any criticism means the critic is a jerk).

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

king_kilr posted:

I know. I should have said "not addressing that *yet*". I'll give Tarek and Jannis all the time they need, but I'm not switching yet.

I'd get off of setuptools as quickly as possible. It's an evolutionary dead-end. The recent debacle between PJE and the rest of the world only solidifies that position. If distribute works; just use it.

king_kilr
May 25, 2007

m0nk3yz posted:

I'd get off of setuptools as quickly as possible. It's an evolutionary dead-end. The recent debacle between PJE and the rest of the world only solidifies that position. If distribute works; just use it.

I'll switch the moment they break backwards compatibility (the sooner the better...). But for now it works pretty well TBH.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Avenging Dentist posted:

I figured. The post was as much for the benefit of others as it was for you (lots of people seriously do think that any criticism means the critic is a jerk).

Well now you've got me refactoring, and for the first time ever I'm going to work on some sort of code design before I start writing actual code.

Of course, by "first time ever" I only mean the past 6 months or so which is when I started to pick up Python and programming in general.

I love criticism from people much more knowledgeable than me, so bring it on.

edit:

...nevermind, I'll think about this more before posting my question...

Thermopyle fucked around with this message at 06:18 on Dec 2, 2009

duck monster
Dec 15, 2004

Anybody know how to convince easy_install not to keep loving up installs by sticking -Wno_long_doubles in CFLAGS when its trying to compile poo poo?

Its driving me mad, since everything wants to use that flag, but the mac simply doesnt support it., or rather should I say the more recent apple GCC toolchains don't appear to.

cc1: error: unrecognized command line option "-Wno-long-double"
cc1: error: unrecognized command line option "-Wno-long-double"
:sigh:

BigRedDot
Mar 6, 2008

Wow, I don't work at a python shop any longer, but all this talk is really dragging me back to the worst part about it. I love python, but packaging/releasing... what a horrible mess.

king_kilr
May 25, 2007

BigRedDot posted:

Wow, I don't work at a python shop any longer, but all this talk is really dragging me back to the worst part about it. I love python, but packaging/releasing... what a horrible mess.

Releasing is easily the biggest pain point right now. Installing stuff is trivial. mkvirtualenv <poo poo im working on>; pip install <poo poo i need>. wee it magically works

Kire
Aug 25, 2006
I wrote myself into a corner with my little text adventure game, I think. I put my main loop inside a function for some reason, but to extricate it (which should be as easy as deleting the def: line and dedenting) I need to figure out how to change the context of the choices offered so that I can switch rooms when the player moves. Right now the code's like:
code:
 
def Choice(location):
    running = True
    while running: 
        main loop which handles the choices like "[t]ake items, [d]rop items, [m]ove..." and uses things like location.print_items() or location.room_inventory.remove(pickedup_item)

outside = Location('You are in front of a white house')
inside = Location('You are inside the house')

Choice(outside)
This worked fine when I just had one room and was only working on getting inventory management working, but now that I want the player to move between rooms I don't know what the best way is to make it change "location" between the outside and inside instances of Location. I only realized the problem when I started to write "if (player wants to move inside): Choice(inside)" inside the definition of Choice!

griliard
May 12, 2006

Kire posted:

I wrote myself into a corner with my little text adventure game, I think. I put my main loop inside a function for some reason, but to extricate it (which should be as easy as deleting the def: line and dedenting) I need to figure out how to change the context of the choices offered so that I can switch rooms when the player moves. Right now the code's like:
code:
 
def Choice(location):
    running = True
    while running: 
        main loop which handles the choices like "[t]ake items, [d]rop items, [m]ove..." and uses things like location.print_items() or location.room_inventory.remove(pickedup_item)

outside = Location('You are in front of a white house')
inside = Location('You are inside the house')

Choice(outside)
This worked fine when I just had one room and was only working on getting inventory management working, but now that I want the player to move between rooms I don't know what the best way is to make it change "location" between the outside and inside instances of Location. I only realized the problem when I started to write "if (player wants to move inside): Choice(inside)" inside the definition of Choice!

I assume Location is an object. If so, just use a current_location variable to keep track of where you are.
code:
def Choice(location):
    #Note: You need to decide where current_location is residing in terms of scope.
    current_location=location
The main loop uses current_location.print_items(), etc.

Xguard86
Nov 22, 2004

"You don't understand his pain. Everywhere he goes he sees women working, wearing pants, speaking in gatherings, voting. Surely they will burn in the white hot flames of Hell"
I'm an MIS (CIS, ISQS whatever your school calls it) major and I'm teaching myself python because I want to understand programming better. Not like CS full time coder level, but I don't fee comfortable with my current, very basic knowledge level. I understand the basic pieces and I've done some stuff in an intro to java class and the little programs in the python tutorials, but I'm looking for more.

Does anyone know of any resources that offer simple projects, with some kind of solution code to check my work? Kind of like the next step to the stuff in the python tutorials linked in this thread.

I've been trying to think of things myself, but I find that they are either too complex for my current level, or I get stuck and can't really figure out what to do. Apologies if I've missed an answer to my question in this thread, I've skimmed through it but didn't see anything.

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe
This needs to go into a CoC FAQ or something.

The usual recommendations are as follows:

  • Get involved with an open source project and start by reading the code and eventually start adding stuff/fixing bugs.
  • Try solve some of the problems at Project Euler. A lot of people get intimidated by the math but some of those problems can teach you a lot about your language of choice.

In your case I think it would be beneficial to start learning about basic data structures and then start using them for more complex things. For instance try creating your own linked list, and then use it for calculating the standard deviation of the numbers.

tehk
Mar 10, 2006

[-4] Flaw: Heart Broken - Tehk is extremely lonely. The Gay Empire's ultimate weapon finds it hard to have time for love.
The problem with Project Euler is you can solve the problems without ever touching the majority of the language's features. Which is not so good for someone who is using python to explore concepts so that he can "apply technology effectively". Though I do really suggest it if you enjoy the math aspect.

There are resources listed on the python wiki for Non Programmers here, and pycon videos here if you want to explore python and various python projects that you can dive into. One presenter gave a python101 talk and others touched on stuff ranging from OOP to deployment if those interest you. If you enjoy lectures there is a nice Intro to CS course on MIT open courseware that focuses on concepts, using python, for CS majors and non majors alike. Things like Crunchy bring web tutorials alive, but I can not speak of their quality because they are fairly new.

tehk fucked around with this message at 02:50 on Dec 6, 2009

duck monster
Dec 15, 2004

duck monster posted:

Anybody know how to convince easy_install not to keep loving up installs by sticking -Wno_long_doubles in CFLAGS when its trying to compile poo poo?

Its driving me mad, since everything wants to use that flag, but the mac simply doesnt support it., or rather should I say the more recent apple GCC toolchains don't appear to.

cc1: error: unrecognized command line option "-Wno-long-double"
cc1: error: unrecognized command line option "-Wno-long-double"
:sigh:

*bangs head on wall*

Mac support for python STILL sucks.

Anybody had any success with easy_install on python in snow leopard or is its interaction with the latest mac GCC considered broken in general? i just can't find any references on the net on tweaking C flags globally for easy install.

good jovi
Dec 11, 2000

'm pro-dickgirl, and I VOTE!

duck monster posted:

*bangs head on wall*

Mac support for python STILL sucks.

Anybody had any success with easy_install on python in snow leopard or is its interaction with the latest mac GCC considered broken in general? i just can't find any references on the net on tweaking C flags globally for easy install.

There's something more wrong with your situation than just Snow Leopard or a newer gcc. I've never seen those errors you're getting, and haven't heard of anyone in my office getting them either.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

It's entirely possible that I'm not using objects right, but...

Is it possible for an class to return a value instead of an object when it's instantiated?

For example, I've got a Film class that tries to determine which movie a file is. When I instantiate the object it parses the filename and uses the API for TMDB to determine if it's got the movie name figured out and then returns an object with title, year, actors, etc.

I'd like the object to just return None or False if it thinks it's not actually a movie.

Of course, I could just set an attribute on the object and then check that attribute later, but I'm mainly just curious if this is possible or if I'm thinking about classes/objects the wrong way.

Allie
Jan 17, 2004

Sailor_Spoon posted:

There's something more wrong with your situation than just Snow Leopard or a newer gcc. I've never seen those errors you're getting, and haven't heard of anyone in my office getting them either.

Sounds like either his distribution of Python is built incorrectly, or the app he's trying to build is adding those flags itself.

Running python-config --cflags will tell you what the default CFLAGS are for building extensions with distutils. If that faulty flag is in there, you probably need to fix/rebuild your Python installation.

Lonely Wolf
Jan 20, 2003

Will hawk false idols for heaps and heaps of dough.

Thermopyle posted:

It's entirely possible that I'm not using objects right, but...

Is it possible for an class to return a value instead of an object when it's instantiated?

For example, I've got a Film class that tries to determine which movie a file is. When I instantiate the object it parses the filename and uses the API for TMDB to determine if it's got the movie name figured out and then returns an object with title, year, actors, etc.

I'd like the object to just return None or False if it thinks it's not actually a movie.

Of course, I could just set an attribute on the object and then check that attribute later, but I'm mainly just curious if this is possible or if I'm thinking about classes/objects the wrong way.

No, that's not possible. Yes, it sounds like you are not using objects right. It sounds like you want is a function that returns a Film object iff it is constructible.

Adbot
ADBOT LOVES YOU

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Thermopyle posted:

It's entirely possible that I'm not using objects right, but...

:words:

Just raise an exception if it fails.

  • Locked thread