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
Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

cinci zoo sniper posted:

what if i dont know the program i need :thunk:
then the program you need is, the compiler

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





i was a huge 'dynamic langs are more productive than static langs' person when my only good options for a static lang were java, c# and c++. things are different here in 2018 tho and i dunno why anyone would choose ruby or python for more than a bash replacement when they can choose from so many static languages that actually take tooling and ergonomics into account

Shaggar
Apr 26, 2006
if you still refuse to use c# and java in 2018 you haven't left that junior dev mindset.

luchadornado
Oct 7, 2004

A boombox is not a toy!

Shaggar posted:

if you still refuse to use c# and java in 2018 you haven't left that junior dev mindset.

i like big runtimes and i cannot lie

Notorious b.s.d.
Jan 25, 2003

by Reene

Gazpacho posted:

people said the same things about VB.net, called it VB.Not and such. so what, legacy VB was trash

vb.net had nothing in common with vb

it's not like "porting vb to vb.net is hard" it's more "vb and vb.net share no APIs, concepts, or syntax"

Notorious b.s.d.
Jan 25, 2003

by Reene

Sapozhnik posted:

Python 3 and python 2 are two different programming languages with similar names so I can see why people might get confused.

this was zed's argument. it was stupid when he put it to paper, and it's still stupid when you say it here.

Bloody
Mar 3, 2013

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

cinci zoo sniper
Mar 15, 2013




the talent deficit posted:

i was a huge 'dynamic langs are more productive than static langs' person when my only good options for a static lang were java, c# and c++. things are different here in 2018 tho and i dunno why anyone would choose ruby or python for more than a bash replacement when they can choose from so many static languages that actually take tooling and ergonomics into account

i dont do software engineering. for what i do, the only language with 3rd party library ecosystem somewhere on python's radar is r

CPColin
Sep 9, 2003

Big ol' smile.

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

Smaller functions are Easier to Reason About™ and could potentially be targeted by unit tests individually before their composed into a complex task.

JawnV6
Jul 4, 2004

So hot ...

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

you should trust the compiler more

Volte
Oct 4, 2004

woosh woosh

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?
the same reason you give your variables meaningful names. a function is a named abstraction.

AggressivelyStupid
Jan 9, 2012

mega functions loving suck to look at

Xarn
Jun 26, 2015

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

It gives things a meaningful name, letting other code become more readable.

Just today, I wrote two functions with a single call site:

code:
def is_black(r, g, b):
    return r == 255 and g == 255 and b == 255
def is_white(r, g, b):
    return r == 0 and g == 0 and b == 0
this made for much more readable call site:

code:
if is_black(*pixel[x, y]):
    ...
elif not is_white(*pixel[x, y]):
    ...

prisoner of waffles
May 8, 2007

Ah! well a-day! what evil looks
Had I from old and young!
Instead of the cross, the fishmech
About my neck was hung.
Go team trying to avoid a Python 2 to Python 3 problem when going from Go 1 to Go 2: https://github.com/golang/proposal/blob/master/design/28221-go2-transitions.md

Go team inventing new keyword (not that dissimilar from defer) to make explicit error-handling a little more elegant than "repeat code everywhere" and "if error goto a block which may be full of if statements": https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

MononcQc
May 29, 2007

I'm kind of amazed at all the attempts for technological solutions to breaking changes here.

It kind of seems to me that if you go the social route and avoid having 15 years of never-breaking changes and instead routinely break a few small things here and there on a well-defined schedule, the habit of small migrations is taken in stride by most of the community. Display big warnings on features to be deprecated, give a few years before taking something out, and off you go.

Maybe I'm just daft but it seems that if people knew and accepted the need that from time to time, you'll need to keep all your libs up to date a little bit and that you could progressively upgrade and do the changes, you wouldn't find yourself in the python (and potentially golang) situation of risking a huge divide of "so many old code bases we can't port in one go" and "I need the new features to work halp." Instead people would be like "Holy poo poo yes bring in the new features, all I have to pay is a small cost of cleaning old poo poo up to get the new stuff." It incentivizes things a bit better, and smoothes the total effort of porting things over longer periods of times and smaller tasks for contributors or corporations.

It would be easier to internalize and amortize the cost it seems to me.

mystes
May 31, 2006

I think the way rust "editions" are supposed to work is that each crate chooses which edition it's using but the new compilers can still compile code using previous editions and a single project can have dependencies that use different editions.

This seems like a decent compromise.

If it was me, based on the python experience I might even go further and allow different sections of the same file to use different versions if this wasn't to crazy to implement.

prisoner of waffles
May 8, 2007

Ah! well a-day! what evil looks
Had I from old and young!
Instead of the cross, the fishmech
About my neck was hung.
Go did do that early in its history with technological solutions. The language was meant to be simple so as to be easily manipulated and "go vet" and "go fix" were reportedly quite helpful as they changed language features and core library APIs

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?

MononcQc posted:

Instead people would be like "Holy poo poo yes bring in the new features, all I have to pay is a small cost of cleaning old poo poo up to get the new stuff." It incentivizes things a bit better, and smoothes the total effort of porting things over longer periods of times and smaller tasks for contributors or corporations.

It would be easier to internalize and amortize the cost it seems to me.

it seems like they would be but the experience with Swift is that developers hate migrating from one language version to another even if there are automated tools to do most of the work for you

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

eschaton posted:

it seems like they would be but the experience with Swift is that developers hate migrating from one language version to another even if there are automated tools to do most of the work for you

it's the same with java. while there might be isolated pockets of developers who get excited about lambdas or streams or var being added, my experience is most view adopting a new level of java (se/ee) as part of the cost of continuing to receive service from oracle/ibm/whoever

MononcQc
May 29, 2007

eschaton posted:

it seems like they would be but the experience with Swift is that developers hate migrating from one language version to another even if there are automated tools to do most of the work for you

they'll always hate it, but to me the actual question is whether they'd hate it more than waiting to put all the breaking changes in just one big release that breaks everything, even with if you introduce about 5-6 different mechanisms to "break but not break things"

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

the talent deficit posted:

i was a huge 'dynamic langs are more productive than static langs' person when my only good options for a static lang were java, c# and c++. things are different here in 2018 tho
:doubt:

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

gradle has been throwing out occasional messages about things being removed in gradle 5.0 for over a year now, can't wait to see how blindsided people try to claim they were

redleader
Aug 18, 2005

Engage according to operational parameters

the talent deficit posted:

i was a huge 'dynamic langs are more productive than static langs' person when my only good options for a static lang were java, c# and c++. things are different here in 2018 tho and i dunno why anyone would choose ruby or python for more than a bash replacement when they can choose from so many static languages that actually take tooling and ergonomics into account

i'm glad u found golang

suffix
Jul 27, 2013

Wheeee!
they called it windows 95 but it's actually a different os than windows 3.11 :thunk:

cinci zoo sniper
Mar 15, 2013




carry on then posted:

gradle has been throwing out occasional messages about things being removed in gradle 5.0 for over a year now, can't wait to see how blindsided people try to claim they were

okay, illl start










maven is good

MononcQc
May 29, 2007

carry on then posted:

gradle has been throwing out occasional messages about things being removed in gradle 5.0 for over a year now, can't wait to see how blindsided people try to claim they were

Build tools are kind of in a special category there, because while a program can support multiple versions of a language, the things that let you do that tend to be related to the build tool you have.

Like it makes sense to vendor the build tool with programs for long term future support, but the build tool I maintain had to forcefully deprecate older versions because they could only build on older language definitions that no longer supported good enough TLS (in fact it only supported SSL) which meant it could no longer interact with packages or github/bitbucket over https, for example.

Funnily enough the previous implementation of the build tool did what I initially asked for -- introduce breaking changes over time -- but it was a nightmare for everyone because that meant that if you wanted to build a project, you not only had to care about the library's version and which language versions it supported, but you also had to know which version of the build tool it used to know if it could be working at all.

Build tools are probably one case where you have to plan for multi-year deprecation schedules that are well communicated because your users care about all the libraries for all the language versions for all the related systems at once and you very hardly can deprecate one bit without huge ripple effects; if your tool drops compat for older language versions, then your tool is preventing language update schedules. We have some partial backwards compat for the older incarnation of the tool, and still today, some projects are actively migrating to the new tool and people can use a config format that's 90% backwards compatible (and has escape hatches otherwise) with a tool that has been unmaintained for ~3-4 years and seemingly has no pre-built copy that can reasonably use TLS1.1

Soricidus
Oct 21, 2010
freedom-hating statist shill

Sapozhnik posted:

Not sure why the creators of python 2 are suddenly out to kill it tho. Doesn't inspire a whole lot of confidence in the ecosystem.

literally an entire decade of notice counts as “suddenly” now?

fritz
Jul 26, 2003

MononcQc posted:

Build tools are kind of in a special category there, because while a program can support multiple versions of a language, the things that let you do that tend to be related to the build tool you have.

Like it makes sense to vendor the build tool with programs for long term future support, but the build tool I maintain had to forcefully deprecate older versions because they could only build on older language definitions that no longer supported good enough TLS (in fact it only supported SSL) which meant it could no longer interact with packages or github/bitbucket over https, for example.

Funnily enough the previous implementation of the build tool did what I initially asked for -- introduce breaking changes over time -- but it was a nightmare for everyone because that meant that if you wanted to build a project, you not only had to care about the library's version and which language versions it supported, but you also had to know which version of the build tool it used to know if it could be working at all.

Build tools are probably one case where you have to plan for multi-year deprecation schedules that are well communicated because your users care about all the libraries for all the language versions for all the related systems at once and you very hardly can deprecate one bit without huge ripple effects; if your tool drops compat for older language versions, then your tool is preventing language update schedules. We have some partial backwards compat for the older incarnation of the tool, and still today, some projects are actively migrating to the new tool and people can use a config format that's 90% backwards compatible (and has escape hatches otherwise) with a tool that has been unmaintained for ~3-4 years and seemingly has no pre-built copy that can reasonably use TLS1.1

cmake's got policies and versioning and it seems to work as ok as anything else

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

suffix posted:

they called it windows 95 but it's actually a different os than windows 3.11 :thunk:
DOS is still deep in windows 10 ... sleeping ...

Sweeper
Nov 29, 2007
The Joe Buck of Posting
Dinosaur Gum
c++ is fine if you use the modern stuff imo, and templates are baller. compile time is the best time :getin:

and tbh python w/ mypy is fine, make sure you enforce types on all method declarations and decorators and it's good enough imo

Sweeper fucked around with this message at 22:42 on Oct 26, 2018

Zlodo
Nov 25, 2006

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

I like not to have to scroll up multiple pages to find a variable definition or a matching curly brace

I have a co-worker who write code like that (he also likes nesting a shitload of ifs) and we're part of the same team and work on the same things and I want to murder him every time I have to fix/optimize/modify something in his giant horrible functions/classes

Sweeper
Nov 29, 2007
The Joe Buck of Posting
Dinosaur Gum

Zlodo posted:

I like not to have to scroll up multiple pages to find a variable definition or a matching curly brace

I have a co-worker who write code like that (he also likes nesting a shitload of ifs) and we're part of the same team and work on the same things and I want to murder him every time I have to fix/optimize/modify something in his giant horrible functions/classes

we've got two 5000+ line files which are incredibly annoying to edit, in those files are many functions more than 200 lines long lol

Captain Foo
May 11, 2004

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

Gazpacho posted:

DOS is still deep in windows 10 ... sleeping ...

msdos.sys and command.com? really?

TheFluff
Dec 13, 2006

FRIENDS, LISTEN TO ME
I AM A SEAGULL
OF WEALTH AND TASTE

Sweeper posted:

c++ is fine if you use the modern stuff imo, and templates are baller. compile time is the best time :getin:

they who program c++ should take care lest they become c++. for when you gaze long into the machine, the machine gazes also into you.

C++ code:
namespace {

struct LoadU8 {
	typedef uint8_t type;

	static inline FORCE_INLINE __m256 load8(const uint8_t *ptr)
	{
		return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i *)ptr)));
	}
};

struct LoadU16 {
	typedef uint16_t type;

	static inline FORCE_INLINE __m256 load8(const uint16_t *ptr)
	{
		return _mm256_cvtepi32_ps(_mm256_cvtepu16_epi32(_mm_load_si128((const __m128i *)ptr)));
	}
};

struct LoadF16 {
	typedef uint16_t type;

	static inline FORCE_INLINE __m256 load8(const uint16_t *ptr)
	{
		return _mm256_cvtph_ps(_mm_load_si128((const __m128i *)ptr));
	}
};

struct LoadF32 {
	typedef float type;

	static inline FORCE_INLINE __m256 load8(const float *ptr)
	{
		return _mm256_load_ps(ptr);
	}
};

struct StoreU8 {
	typedef uint8_t type;

	static inline FORCE_INLINE void store16(uint8_t *ptr, __m256i x)
	{
		_mm_store_si128((__m128i *)ptr, mm256_cvtusepi16_epi8(x));
	}

	static inline FORCE_INLINE void store16_idxlo(uint8_t *ptr, __m256i x, unsigned idx)
	{
		mm_store_idxlo_epi8((__m128i *)ptr, mm256_cvtusepi16_epi8(x), idx);
	}

	static inline FORCE_INLINE void store16_idxhi(uint8_t *ptr, __m256i x, unsigned idx)
	{
		mm_store_idxhi_epi8((__m128i *)ptr, mm256_cvtusepi16_epi8(x), idx);
	}
};

struct StoreU16 {
	typedef uint16_t type;

	static inline FORCE_INLINE void store16(uint16_t *ptr, __m256i x) { _mm256_store_si256((__m256i *)ptr, x); }

	static inline FORCE_INLINE void store16_idxlo(uint16_t *ptr, __m256i x, unsigned idx) { mm256_store_idxlo_epi16((__m256i *)ptr, x, idx); }

	static inline FORCE_INLINE void store16_idxhi(uint16_t *ptr, __m256i x, unsigned idx) { mm256_store_idxhi_epi16((__m256i *)ptr, x, idx); }
};


template <class Load, class Store>
inline FORCE_INLINE void ordered_dither_avx2_impl(const float *dither, unsigned dither_offset, unsigned dither_mask,
                                                  const void *src, void *dst, float scale, float offset, unsigned bits, unsigned left, unsigned right)
{
	const typename Load::type *src_p = static_cast<const typename Load::type *>(src);
	typename Store::type *dst_p = static_cast<typename Store::type *>(dst);

	unsigned vec_left = ceil_n(left, 16);
	unsigned vec_right = floor_n(right, 16);

	const __m256 scale_ps = _mm256_set1_ps(scale);
	const __m256 offset_ps = _mm256_set1_ps(offset);
	const __m256i out_max = _mm256_set1_epi16(static_cast<uint16_t>((1 << bits) - 1));

#define XARGS dither, dither_offset, dither_mask, scale_ps, offset_ps, out_max
	if (left != vec_left) {
		__m256 lo = Load::load8(src_p + vec_left - 16 + 0);
		__m256 hi = Load::load8(src_p + vec_left - 16 + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, vec_left - 16, XARGS);
		Store::store16_idxhi(dst_p + vec_left - 16, x, left % 16);
	}
	for (unsigned j = vec_left; j < vec_right; j += 16) {
		__m256 lo = Load::load8(src_p + j + 0);
		__m256 hi = Load::load8(src_p + j + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, j, XARGS);
		Store::store16(dst_p + j, x);
	}
	if (right != vec_right) {
		__m256 lo = Load::load8(src_p + vec_right + 0);
		__m256 hi = Load::load8(src_p + vec_right + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, vec_right, XARGS);
		Store::store16_idxlo(dst_p + vec_right, x, right % 16);
	}
#undef XARGS
}

} // namespace
you'd think you can't have generics if you're handwriting SIMD assembler, but since c++ exists, you'd be wrong! however, c++ templates, c preprocessor macros and avx2 intrinsics all at the same time is just a little bit too much

source, some functions omitted

TheFluff fucked around with this message at 23:37 on Oct 26, 2018

MrMoo
Sep 14, 2000

Bloody posted:

why do people split things into a bunch of little functions and then use those functions in exactly one place. why is this a pattern?

The Carmack changed his mind on this on his Twitter feed, before he used to like functions for abstraction, testing, future reuse, type stuff, and now he prefers the code inline for better understanding of what the code is actually doing within a larger context.

In JS land the optimiser works on the size of the function so I like to use nested functions to get the best of both worlds, I have local context and can use super generic terms that make it easier to read. This applies especially to promise chains that become unreadable with too much inline lambda code.

MrMoo fucked around with this message at 23:43 on Oct 26, 2018

redleader
Aug 18, 2005

Engage according to operational parameters

Sweeper posted:

we've got two 5000+ line files which are incredibly annoying to edit, in those files are many functions more than 200 lines long lol

7k line js file. 1700 of those lines are in a jQuery onload handler. i feel you

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man

TheFluff posted:

they who program c++ should take care lest they become c++. for when you gaze long into the machine, the machine gazes also into you.

C++ code:
namespace {

struct LoadU8 {
	typedef uint8_t type;

	static inline FORCE_INLINE __m256 load8(const uint8_t *ptr)
	{
		return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i *)ptr)));
	}
};

struct LoadU16 {
	typedef uint16_t type;

	static inline FORCE_INLINE __m256 load8(const uint16_t *ptr)
	{
		return _mm256_cvtepi32_ps(_mm256_cvtepu16_epi32(_mm_load_si128((const __m128i *)ptr)));
	}
};

struct LoadF16 {
	typedef uint16_t type;

	static inline FORCE_INLINE __m256 load8(const uint16_t *ptr)
	{
		return _mm256_cvtph_ps(_mm_load_si128((const __m128i *)ptr));
	}
};

struct LoadF32 {
	typedef float type;

	static inline FORCE_INLINE __m256 load8(const float *ptr)
	{
		return _mm256_load_ps(ptr);
	}
};

struct StoreU8 {
	typedef uint8_t type;

	static inline FORCE_INLINE void store16(uint8_t *ptr, __m256i x)
	{
		_mm_store_si128((__m128i *)ptr, mm256_cvtusepi16_epi8(x));
	}

	static inline FORCE_INLINE void store16_idxlo(uint8_t *ptr, __m256i x, unsigned idx)
	{
		mm_store_idxlo_epi8((__m128i *)ptr, mm256_cvtusepi16_epi8(x), idx);
	}

	static inline FORCE_INLINE void store16_idxhi(uint8_t *ptr, __m256i x, unsigned idx)
	{
		mm_store_idxhi_epi8((__m128i *)ptr, mm256_cvtusepi16_epi8(x), idx);
	}
};

struct StoreU16 {
	typedef uint16_t type;

	static inline FORCE_INLINE void store16(uint16_t *ptr, __m256i x) { _mm256_store_si256((__m256i *)ptr, x); }

	static inline FORCE_INLINE void store16_idxlo(uint16_t *ptr, __m256i x, unsigned idx) { mm256_store_idxlo_epi16((__m256i *)ptr, x, idx); }

	static inline FORCE_INLINE void store16_idxhi(uint16_t *ptr, __m256i x, unsigned idx) { mm256_store_idxhi_epi16((__m256i *)ptr, x, idx); }
};


template <class Load, class Store>
inline FORCE_INLINE void ordered_dither_avx2_impl(const float *dither, unsigned dither_offset, unsigned dither_mask,
                                                  const void *src, void *dst, float scale, float offset, unsigned bits, unsigned left, unsigned right)
{
	const typename Load::type *src_p = static_cast<const typename Load::type *>(src);
	typename Store::type *dst_p = static_cast<typename Store::type *>(dst);

	unsigned vec_left = ceil_n(left, 16);
	unsigned vec_right = floor_n(right, 16);

	const __m256 scale_ps = _mm256_set1_ps(scale);
	const __m256 offset_ps = _mm256_set1_ps(offset);
	const __m256i out_max = _mm256_set1_epi16(static_cast<uint16_t>((1 << bits) - 1));

#define XARGS dither, dither_offset, dither_mask, scale_ps, offset_ps, out_max
	if (left != vec_left) {
		__m256 lo = Load::load8(src_p + vec_left - 16 + 0);
		__m256 hi = Load::load8(src_p + vec_left - 16 + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, vec_left - 16, XARGS);
		Store::store16_idxhi(dst_p + vec_left - 16, x, left % 16);
	}
	for (unsigned j = vec_left; j < vec_right; j += 16) {
		__m256 lo = Load::load8(src_p + j + 0);
		__m256 hi = Load::load8(src_p + j + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, j, XARGS);
		Store::store16(dst_p + j, x);
	}
	if (right != vec_right) {
		__m256 lo = Load::load8(src_p + vec_right + 0);
		__m256 hi = Load::load8(src_p + vec_right + 8);
		__m256i x = ordered_dither_avx2_xiter(lo, hi, vec_right, XARGS);
		Store::store16_idxlo(dst_p + vec_right, x, right % 16);
	}
#undef XARGS
}

} // namespace
you'd think you can't have generics if you're handwriting SIMD assembler, but since c++ exists, you'd be wrong! however, c++ templates, c preprocessor macros and avx2 intrinsics all at the same time is just a little bit too much

source, some functions omitted

this is boost level powerful. I bow the head

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?

MononcQc posted:

older language definitions that no longer supported good enough TLS (in fact it only supported SSL)

uh why does TLS support have anything to do with language version

Lutha Mahtin
Oct 10, 2010

Your brokebrain sin is absolved...go and shitpost no more!

eschaton posted:

uh why does TLS support have anything to do with language version

1. the build tool can fetch dependencies from the net
2. the tool has multiple versions
3. some older version(s) of the tool only work with older version(s) of the language it's written in
4. some of these older version(s) of the language only support old, deprecated versions of SSL/TLS
5. many websites no longer support old deprecated versions of SSL/TLS any more
6. thus these old versions of the tool will now be unable to fetch dependencies securely from the net

Adbot
ADBOT LOVES YOU

FamDav
Mar 29, 2008

Shaggar posted:

if you still refuse to use c# and java in 2018 you haven't left that junior dev mindset.

java is aesthetic as gently caress @ your mother

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